<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>AFPy&#39;s Planet</title>
    <subtitle>MakeMake The Dwarf Planet is a feed agregator.</subtitle>
    <link href="https://planet.afpy.org/atom.xml" rel="self" />
    <link href="https://planet.afpy.org/" />
    <id>https://planet.afpy.org/atom.xml</id>
    <updated>2026-05-20T02:40:09Z</updated>
    <entry>
        <title>Django Debug Toolbar Checkbox</title>
        <link href="https://discuss.afpy.org/t/django-debug-toolbar-checkbox/3011" />
        <id>https://discuss.afpy.org/t/django-debug-toolbar-checkbox/3011</id>
        <updated>2026-05-16T23:15:52Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>J’ai longtemps eu une petite interface d’admin Django pour activer / désactiver la debug toolbar (même en prod), dans plusieurs projets, j’ai décidé de le packager :</p>
<p><img alt="" height="221" src="https://git.afpy.org/mdk/debug-toolbar-checkbox/media/branch/main/debug-toolbar.gif" width="586"/></p>
<p>Le paquet est là : <a href="https://pypi.org/project/django-debug-toolbar-checkbox/">https://pypi.org/project/django-debug-toolbar-checkbox/</a><br/>
Le code est là : <a class="inline-onebox" href="https://git.afpy.org/mdk/debug-toolbar-checkbox">mdk/debug-toolbar-checkbox - La forge de l'AFPy</a></p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/django-debug-toolbar-checkbox/3011">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Le pastèque de https://p.afpy.org gère maintenant le binaire</title>
        <link href="https://discuss.afpy.org/t/le-pasteque-de-https-p-afpy-org-gere-maintenant-le-binaire/3010" />
        <id>https://discuss.afpy.org/t/le-pasteque-de-https-p-afpy-org-gere-maintenant-le-binaire/3010</id>
        <updated>2026-05-16T15:38:18Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Le repo : <a class="inline-onebox" href="https://git.afpy.org/AFPy/pasteque">AFPy/pasteque - La forge de l'AFPy</a></p>
<p>Avant un <code>paf /bin/ls</code> faisait crasher le serveur, sniff… Je ne vois pas trop l’intérêt d’envoyer du binaire mais bon l’autoriser était un bon moyen de corriger le bug.</p>
<pre><code class="lang-shell">$ paf afpy/static/images/favicon.ico
- https://p.afpy.org/43A6/afpy/static/images/favicon.ico

$ sha1sum afpy/static/images/favicon.ico
d39d104c083a013d4cf48f456f91bcc9fe905ac4  afpy/static/images/favicon.ico

$ curl https://p.afpy.org/43A6/afpy/static/images/favicon.ico | sha1sum
d39d104c083a013d4cf48f456f91bcc9fe905ac4  -

$ wget https://p.afpy.org/43A6/afpy/static/images/favicon.ico
2026-05-16 16:37:25 (20,8 MB/s) — « favicon.ico » sauvegardé [1150/1150]
</code></pre>
<p>Et pour la vue HTML je sort un hexdump : <a class="inline-onebox" href="https://p.afpy.org/43A6/afpy/static/images/favicon.ico">favicon.ico</a></p>
<p><small>4 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/le-pasteque-de-https-p-afpy-org-gere-maintenant-le-binaire/3010">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>ELY - Un agent IA auto-hébergé conforme RGPD avec anonymisation native</title>
        <link href="https://linuxfr.org/users/elydefranck/journaux/ely-un-agent-ia-auto-heberge-conforme-rgpd-avec-anonymisation-native" />
        <id>https://linuxfr.org/users/elydefranck/journaux/ely-un-agent-ia-auto-heberge-conforme-rgpd-avec-anonymisation-native</id>
        <updated>2026-05-14T14:24:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>Avis à tous ceux qui vont hurler sur un projet vibe codé mais pour ceux qui veulent tester et que ça intéresse, j'ai créé ELY. Un agent IA auto-hébergé que je développe depuis plusieurs mois et même si j'ai fait ça avec Claude Code, croyez moi, je n'ai pas eu qu'à dire "Fais moi ceci, comme cela, qui fait çi et qui fait ça…". C'est le fruit de week-end et de soirées, voire nuits, à imaginer, tester, échanger jusqu'à ce que le résultat me convienne.</p>
<p>La particularité — et la raison d'être du projet — est un pipeline d'anonymisation des données personnelles qui s'exécute AVANT tout appel à un LLM, qu'il soit local ou cloud.</p>
<p>L'écosystème des agents IA a beaucoup grandi en 2025-2026 (OpenClaw, Hermes, et bientôt Google Remy à I/O 2026), mais aucun n'adresse sérieusement le cas des organisations soumises au secret professionnel ou au RGPD strict. ELY essaie de combler ce vide.</p>
<p>Quand un avocat copie une note de synthèse dans ChatGPT, ou qu'un expert-comptable demande à Claude de résumer un compte de résultat client, les noms, IBAN, SIRET, montants — tout part en clair vers des serveurs aux États-Unis. C'est documenté, c'est connu, c'est pourtant fait quotidiennement par des centaines de milliers de professionnels en France.</p>
<p>Les agents auto-hébergés actuels (Hermes, OpenClaw, Aider) règlent le problème de la "boîte noire" en mettant le code à disposition, mais ne résolvent pas le problème des données : si l'agent appelle Claude ou GPT-5 en backend, les données partent quand même.</p>
<p>ELY ajoute une couche d'anonymisation déterministe en amont : avant toute construction de prompt, un SecurityFilter détecte et remplace les PII (emails, IBAN, SIRET, numéros de téléphone, jetons API…) par des placeholders. Le LLM voit <code>[EMAIL_0]</code>, <code>[IBAN_0]</code>. Les valeurs réelles sont restaurées localement quand la réponse revient à l'utilisateur. <strong>Le LLM ne voit jamais la donnée brute.</strong></p>
<p><strong>Architecture</strong></p>
<p>ELY est construit sur :<br/>
- FastAPI + LangGraph (backend Python)<br/>
- Next.js 16 (frontend)<br/>
- Apps natives iOS (SwiftUI) et Android (Kotlin/Compose)<br/>
- Daemon Go pour l'automatisation desktop<br/>
- Qdrant pour la mémoire vectorielle locale, SQLite FTS5 pour le keyword<br/>
- Docker Compose pour le déploiement</p>
<p>Le routage LLM se fait par "tier de complexité" (Tier A rapide / B standard / C profond / IMG / SYS). L'utilisateur assigne un modèle à chaque tier dans les Settings — local (Ollama, LM Studio) pour les tâches simples, cloud (Mistral privilégié, ou Anthropic, OpenAI, Gemini, DeepSeek, Qwen, etc… selon préférence) pour les complexes. Tout est configurable sans redémarrage.</p>
<p><strong>HITL (Human In The Loop) structurel</strong></p>
<p>Toute action irréversible — envoi de mail, suppression, commande SSH, partage — passe par une validation explicite. Trois choix : autoriser une fois, refuser, ou bannir définitivement (la décision persiste entre toutes les sessions futures).</p>
<p>C'est différent des "confirmations" qu'on trouve sur les agents cloud type ChatGPT Operator, où le HITL est une UX optionnelle. Chez ELY, c'est structurel — désactiver HITL demande une modification du code source, ce qui est explicitement interdit par la licence.</p>
<p><strong>Licence</strong></p>
<p>ELY est sous licence PolyForm Strict 1.0 — source-available, <strong>gratuit pour usage personnel/familial/éducatif</strong>, licence commerciale annuelle pour les entreprises.<br/>
C'est un choix conscient, je l'assume :<br/>
l'open-source au sens OSI ne permettait pas de pérenniser le projet sans capital-risque, et la licence MIT/Apache aurait permis à un acteur cloud US de forker pour son SaaS sans aucune contrepartie (J'ai déjà donné…).<br/>
Ce modèle source-available est devenu courant (Sentry, Grafana, Elastic) et fonctionne bien pour les projets entre solo-dev et fondation.</p>
<p><strong>Démarrage</strong></p>
<p>git clone <a href="https://github.com/franckolv-dev/ElyAgent.git">https://github.com/franckolv-dev/ElyAgent.git</a><br/>
cd ElyAgent<br/>
cp .env.example .env<br/>
make up</p>
<p>Trois commandes, 30 minutes pour le scénario "POC local" avec une clé API Gemini gratuite. Documentation et scénarios de déploiement plus avancés (Cloudflare Tunnel, Tailscale, multi-canaux) dans docs/START_HERE.md.</p>
<p><strong>Discussions et critiques bienvenues</strong></p>
<p>C'est un projet personnel développé en parallèle de mon activité professionnelle (je suis directeur technique chez un gros intégrateur Français, spécialisé webtoprint). Le code est ouvert, les choix architecturaux documentés. Toutes les critiques techniques sont les bienvenues, c'est ce qui fait monter le niveau, du moment que c'est constructif.</p>
<p>GitHub : <a href="https://github.com/franckolv-dev/ElyAgent">https://github.com/franckolv-dev/ElyAgent</a><br/>
Site : <a href="https://agent-ely.fr">https://agent-ely.fr</a></p>
<div><a href="https://linuxfr.org/users/elydefranck/journaux/ely-un-agent-ia-auto-heberge-conforme-rgpd-avec-anonymisation-native.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143397/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/elydefranck/journaux/ely-un-agent-ia-auto-heberge-conforme-rgpd-avec-anonymisation-native#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>ElyDeFranck</name>
        </author>
    </entry>
    <entry>
        <title>Présentation d’un générateur de mots de passe Python/Tkinter (standalone Nuitka, multi‑OS, clé USB)</title>
        <link href="https://linuxfr.org/users/securepass/journaux/presentation-d-un-generateur-de-mots-de-passe-python-tkinter-standalone-nuitka-multi-os-cle-usb" />
        <id>https://linuxfr.org/users/securepass/journaux/presentation-d-un-generateur-de-mots-de-passe-python-tkinter-standalone-nuitka-multi-os-cle-usb</id>
        <updated>2026-05-13T17:07:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://escapecyber.blogspot.com/p/captures-escapecyber-tests-techniques.html">Page de test EscapeCyber</a> <br/>
<strong>Bonjour,</strong><br/>
Je souhaite présenter un petit projet personnel : un générateur de mots de passe écrit en Python/Tkinter, compilé en standalone via Nuitka, et destiné à fonctionner directement depuis une clé USB (Ventoy).</p>
<pre><code>    **Origine du projet**``
</code></pre>
<p>Comme beaucoup d’utilisateurs, j’en avais assez de :<br/>
devoir créer des mots de passe différents selon les sites,<br/>
me faire refuser un mot de passe pour un symbole manquant,<br/>
revenir sur “mot de passe oublié”,<br/>
recommencer plusieurs fois sur différents services.<br/>
J’ai aussi constaté que beaucoup utilisent encore des mots de passe basés sur des données personnelles (chien, date de naissance, etc.), ce qui n’est ni sécurisé ni sécurisable.<br/>
L’objectif : un outil simple, portable, robuste, qui génère des mots de passe fiables sans prise de tête.</p>
<pre><code>    ** Fonctionnalités**``
</code></pre>
<p>3 niveaux de complexité : simple (sans symboles), standard (symboles courants), avancé (tous symboles).<br/>
Longueur configurable : 6 à 32 caractères.<br/>
Disponible en 15 langues.<br/>
Génération aléatoire via un algorithme interne.<br/>
Protection par mot de passe à l’ouverture.<br/>
Utilisation de HMAC et bcrypt.<br/>
Compilation Nuitka standalone (pas de dépendances externes).<br/>
Fonctionne sur :<br/>
- Windows 7 → 11<br/>
- Linux Lite 7.04<br/>
- Ubuntu 24.04 LTS<br/>
et probablement la majorité des distributions.</p>
<pre><code>    ** Comportement sous Linux (console automatique)**``
</code></pre>
<p>Lors du lancement du binaire standalone sous Linux, une console s’ouvre automatiquement, puis la fenêtre Tkinter apparaît. Ce comportement est normal avec Nuitka : le binaire reste considéré comme une application console + GUI, et Linux ouvre un terminal pour gérer stdout/stderr.<br/>
La console ne demande rien, ne nécessite aucune action, et le programme fonctionne normalement.</p>
<pre><code>    ** Vision du projet**``
</code></pre>
<p>À terme, je souhaite ajouter un coffre-fort compartimenté (par lettre ou catégorie), afin d’éviter l’exposition d’un lot complet de mots de passe. Les personnes travaillant en cybersécurité comprendront l’intérêt : limiter la surface d’attaque.</p>
<pre><code>    ** Distribution possible**``
</code></pre>
<p>Le projet se veut d’utilité publique. Il pourrait être distribué par :<br/>
banques,<br/>
assurances,<br/>
entreprises,<br/>
associations (ex : protection de profils exposés en ligne).</p>
<pre><code>    ** Support**``
</code></pre>
<p>Une page dédiée sur mon blog documentera :<br/>
- les comportements selon les distributions,<br/>
- les limitations (ex : console automatique),<br/>
- les solutions,<br/>
- les mises à jour,<br/>
- un contact administrateur.</p>
<pre><code>    ** Pourquoi je poste ici**
</code></pre>
<p>Je viens chercher :<br/>
- des retours techniques,<br/>
- des critiques constructives,<br/>
- des tests sur d’autres distributions,<br/>
- des avis sur la partie sécurité.<br/>
Projet personnel, développé par moi-même, sans IA. Merci pour vos retours.</p>
<p>Quelques captures pour illustrer le fonctionnement :<br/>
 – lancement sous Linux (console + interface Tkinter) <br/>
– génération d’un mot de passe <br/>
– interface en différentes langues <br/>
– version Windows<br/>
 – test de la fonction japonais (sans mot de passe sur cette machine) <br/>
<img alt="capture linux lite 7.4" src="https://img.linuxfr.org/img/68747470733a2f2f626c6f676765722e676f6f676c6575736572636f6e74656e742e636f6d2f696d672f622f523239765a32786c2f4156765873456a5174427731334c3951534131746658536232732d3466307a44636f395136427a32307032725a49534c6a6e626249724375563135387654704644425f586d345744424a6875573145456d3678596e6d423935534e35446e6764546256692d695471433352674f614b4f64463656794d72374e696b4a416b7277466363363552662d326a7a45564172363579326262577332306f354274344c5f486d42686f3165446b3335344c47706a52534f4648304279496662334770525f346f672f73313039392f43617074757265253230666c6f75746167652532302532305f6c696e75786c6974655f67656e657261746575722532306d64702532304d61692532305f323032362e706e67/Capture%20floutage%20%20_linuxlite_generateur%20mdp%20Mai%20_2026.png" title="Source : https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQtBw13L9QSA1tfXSb2s-4f0zDco9Q6Bz20p2rZISLjnbbIrCuV158vTpFDB_Xm4WDBJhuW1EEm6xYnmB95SN5DngdTbVi-iTqC3RgOaKOdF6VyMr7NikJAkrwFcc65Rf-2jzEVAr65y2bbWs20o5Bt4L_HmBho1eDk354LGpjRSOFH0ByIfb3GpR_4og/s1099/Capture%20floutage%20%20_linuxlite_generateur%20mdp%20Mai%20_2026.png"/>&gt; <br/>
<img alt="Capture sous windows 10 famille" src="https://img.linuxfr.org/img/68747470733a2f2f626c6f676765722e676f6f676c6575736572636f6e74656e742e636f6d2f696d672f622f523239765a32786c2f4156765873456841754142552d7556583143585976794a6e664c6766306b785a6a70534254734447546c336f38504e4a4e343976306f753934354e3247365462725f39616d6871397270746f727074776274394f77656332324474753032744c58674c6a3563644949497033434d5537484835472d53384a626934475844526838617a54346d5055336f6270347031794b44574a665f336368732d5f73644b304948465a31316a77524e716a4678455932727a724432557844726b50536f6e752d46632f73313134342f43617074757265253230253230666c6f75746167652532306275696c6425323057696e646f7773253230313025323066616d696c6c6525323067656e657261746575725f6d64705f737461626c652e504e47/Capture%20%20floutage%20build%20Windows%2010%20famille%20generateur_mdp_stable.PNG" title="Source : https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAuABU-uVX1CXYvyJnfLgf0kxZjpSBTsDGTl3o8PNJN49v0ou945N2G6Tbr_9amhq9rptorptwbt9Owec22Dtu02tLXgLj5cdIIIp3CMU7HH5G-S8Jbi4GXDRh8azT4mPU3obp4p1yKDWJf_3chs-_sdK0IHFZ11jwRNqjFxEY2rzrD2UxDrkPSonu-Fc/s1144/Capture%20%20floutage%20build%20Windows%2010%20famille%20generateur_mdp_stable.PNG"/> <br/>
<img alt="Capture Ubuntu 24.04" src="https://img.linuxfr.org/img/68747470733a2f2f626c6f676765722e676f6f676c6575736572636f6e74656e742e636f6d2f696d672f622f523239765a32786c2f41567658734567356c467864554c78473067625874566137534e324f7767584d74514963455a61637554533175584c6c4c344c7462496c486a5532556d5a7a684443343135574a454858746d765971425f557a455f666232332d43614f544e683150646d5448635335426e4b415754436d49744145633261576855417878516c30686f50704267687530325f7350573275375051575963566779445f68534a365f4f54454536553772596f6368415a73584c52504d5a3731774d6f67787363507166412f73313338332f636170747572655f67656e657261746575726d64705f6c696e757832342e34253230737461626c652532306a61706f6e6169732e626d70/capture_generateurmdp_linux24.4%20stable%20japonais.bmp" title="Source : https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5lFxdULxG0gbXtVa7SN2OwgXMtQIcEZacuTS1uXLlL4LtbIlHjU2UmZzhDC415WJEHXtmvYqB_UzE_fb23-CaOTNh1PdmTHcS5BnKAWTCmItAEc2aWhUAxxQl0hoPpBghu02_sPW2u7PQWYcVgyD_hSJ6_OTEE6U7rYochAZsXLRPMZ71wMogxscPqfA/s1383/capture_generateurmdp_linux24.4%20stable%20japonais.bmp"/> <br/>
<img alt="Capture windows 11" src="https://img.linuxfr.org/img/68747470733a2f2f626c6f676765722e676f6f676c6575736572636f6e74656e742e636f6d2f696d672f622f523239765a32786c2f41567658734567494a396b72507136716454636a342d626e4255685961553461397931654b424e55705076577769474a5568507779625656454979786e4a67316169356145613169387447486c61716867623049326f6f356548647a7179546272652d644c38714b41364e5f5662376e557949426e774337614f7830515f434a4737686931724f305075754e504448756a75632d5a704b7149484f784e534d6768353265484958626839555f6478707974697076356c6730425f34534c367355665a732f73313438322f43617074757265253230666c6f75746167652532306275696c642532305f67656e657261746575725f6d64705f77696e31312532306176656325323066656e657472652532306d6f7425323064652532307061737365253230696e76616c69642e706e67/Capture%20floutage%20build%20_generateur_mdp_win11%20avec%20fenetre%20mot%20de%20passe%20invalid.png" title="Source : https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIJ9krPq6qdTcj4-bnBUhYaU4a9y1eKBNUpPvWwiGJUhPwybVVEIyxnJg1ai5aEa1i8tGHlaqhgb0I2oo5eHdzqyTbre-dL8qKA6N_Vb7nUyIBnwC7aOx0Q_CJG7hi1rO0PuuNPDHujuc-ZpKqIHOxNSMgh52eHIXbh9U_dxpytipv5lg0B_4SL6sUfZs/s1482/Capture%20floutage%20build%20_generateur_mdp_win11%20avec%20fenetre%20mot%20de%20passe%20invalid.png"/> </p>
<div><a href="https://linuxfr.org/users/securepass/journaux/presentation-d-un-generateur-de-mots-de-passe-python-tkinter-standalone-nuitka-multi-os-cle-usb.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143387/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/securepass/journaux/presentation-d-un-generateur-de-mots-de-passe-python-tkinter-standalone-nuitka-multi-os-cle-usb#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>securepass</name>
        </author>
    </entry>
    <entry>
        <title>La prochaine PyconFR sera à Biarritz !</title>
        <link href="https://linuxfr.org/users/chadys/liens/la-prochaine-pyconfr-sera-a-biarritz" />
        <id>https://linuxfr.org/users/chadys/liens/la-prochaine-pyconfr-sera-a-biarritz</id>
        <updated>2026-05-13T14:03:05Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.pycon.fr/2026/">https://www.pycon.fr/2026/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143383/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/chadys/liens/la-prochaine-pyconfr-sera-a-biarritz#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Chadys</name>
        </author>
    </entry>
    <entry>
        <title>Avec l&#39;IA, Rust et Go peuvent remplacer Python (et le font)</title>
        <link href="https://linuxfr.org/users/pas_pey/liens/avec-l-ia-rust-et-go-peuvent-remplacer-python-et-le-font" />
        <id>https://linuxfr.org/users/pas_pey/liens/avec-l-ia-rust-et-go-peuvent-remplacer-python-et-le-font</id>
        <updated>2026-05-12T06:51:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://medium.com/@NMitchem/if-ai-writes-your-code-why-use-python-bf8c4ba1a055">https://medium.com/@NMitchem/if-ai-writes-your-code-why-use-python-bf8c4ba1a055</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143359/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/pas_pey/liens/avec-l-ia-rust-et-go-peuvent-remplacer-python-et-le-font#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>pas_pey</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Crème CRM en version 2.8</title>
        <link href="https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-8" />
        <id>https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-8</id>
        <updated>2026-05-11T08:11:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Le 7 avril 2026 est sortie la version 2.8 du logiciel de gestion de la relation client Crème CRM (sous licence AGPL-3.0).</p>
<p><img alt="Icone de Crème CRM" src="https://img.linuxfr.org/img/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f487962697264436f72702f6372656d655f63726d2f6d61696e2f6372656d652f7374617469632f636f6d6d6f6e2f696d616765732f6372656d655f3230302e706e67/creme_200.png" title="Source : https://raw.githubusercontent.com/HybirdCorp/creme_crm/main/creme/static/common/images/creme_200.png"/></p>
<p>Au programme notamment, de nombreuses améliorations autour des droits, l’épinglage de fiches et des totaux calculés dans les vues en liste. Les nouveautés sont détaillées dans la suite de la dépêche.</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/117523" hreflang="fr" title="https://cremecrm.com/">Site officiel</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/117524" hreflang="fr" title="https://demos.cremecrm.com">Démo en ligne</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/117525" hreflang="en" title="https://github.com/HybirdCorp/creme_crm">Le dépôt de source</a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/117526" hreflang="en" title="https://hub.docker.com/r/cremecrm/cremecrm-demo">Images Docker de démo</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-description-du-logiciel">Description du logiciel</a></li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-principales-nouveaut%C3%A9s-de-la-version-28">Principales nouveautés de la version 2.8</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-meilleure-synchronisation-avec-les-sorties-de-django">Meilleure synchronisation avec les sorties de Django</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-am%C3%A9liorations-des-droits">Améliorations des droits</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-%C3%89pinglage-de-fiche">Épinglage de fiche</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-totaux-calcul%C3%A9s-dans-les-vues-en-liste">Totaux calculés dans les vues en liste</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-am%C3%A9lioration-des-champs-personnalis%C3%A9s">Amélioration des champs personnalisés</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-quelques-autres-am%C3%A9liorations-notables">Quelques autres améliorations notables</a></li>
</ul>
</li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-le-futur">Le futur</a></li>
</ul>
<h2 id="toc-description-du-logiciel">Description du logiciel</h2>
<p>Crème CRM est un logiciel de <a href="https://fr.wikipedia.org/wiki/Gestion_de_la_relation_client">gestion de la relation client</a>, généralement appelé CRM (pour Customer Relationship Management). Il dispose évidemment des fonctionnalités basiques d’un tel logiciel :</p>
<ul>
<li>un annuaire, dans lequel on enregistre contacts et sociétés : il peut s’agir de clients, bien sûr, mais aussi de partenaires, prospects, fournisseurs, adhérents, etc. ;</li>
<li>un calendrier pour gérer ses rendez‐vous, appels téléphoniques, conférences, etc. ; chaque utilisateur peut avoir plusieurs calendriers, publics ou privés ;</li>
<li>les opportunités d’affaires, gérant tout l’historique des ventes ;</li>
<li>les actions commerciales, avec leurs objectifs à remplir ;</li>
<li>les documents (fichiers) et les classeurs.</li>
</ul>
<p>Crème CRM dispose en outre de nombreux modules optionnels le rendant très polyvalent :</p>
<ul>
<li>campagnes de courriels ;</li>
<li>devis, bons de commande, factures et avoirs ;</li>
<li>tickets, génération des rapports et graphiques…</li>
</ul>
<p>L’objectif de Crème CRM est de fournir un logiciel libre de gestion de la relation client pouvant convenir à la plupart des besoins, simples ou complexes. À cet effet, il propose quelques concepts puissants qui se combinent entre eux (entités, relations, filtres, vues, propriétés, blocs), et il est très configurable (bien des problèmes pouvant se résoudre par l’interface de configuration) ; la contrepartie est qu’il faudra sûrement passer quelques minutes dans l’interface de configuration graphique pour avoir quelque chose qui vous convienne vraiment (la configuration par défaut ne pouvant être optimale pour tout le monde). De plus, afin de satisfaire les besoins les plus particuliers, son code est conçu pour être facilement étendu, tel un cadriciel (<em>framework</em>).</p>
<p>Du côté de la technique, Crème CRM est codé notamment avec Python/Django et fonctionne avec les bases de données MySQL, SQLite et PostgreSQL.</p>
<h2 id="toc-principales-nouveautés-de-la-version-28">Principales nouveautés de la version 2.8</h2>
<p>Voici les changements les plus notables de cette version :</p>
<h3 id="toc-meilleure-synchronisation-avec-les-sorties-de-django">Meilleure synchronisation avec les sorties de Django</h3>
<p>C’est une version plus petite qu’à l’accoutumée (Creme 2.7 est sortie le 2 septembre 2025 et nous sortons une version par an). Cela nous permet de nous caler enfin sur les cycles de sortie de Django (dont les versions LTS—gérée pendant 3 ans—sortent en avril une fois tous les 2 ans) et donc éviter d’avoir des périodes où une version de Crème CRM est encore gérée mais pas la version de Django sous-jacente.</p>
<h3 id="toc-améliorations-des-droits">Améliorations des droits</h3>
<p>Les utilisateurs peuvent avoir plusieurs rôles. Il arrive que des personnes aient plusieurs casquettes, et finissent par posséder plusieurs utilisateurs, se connectant avec le bon utilisateur en fonction des tâches à effectuer. Mais c’est un peu contraignant de devoir à chaque fois se déconnecter puis se reconnecter (et ça peut aussi être gênant d’avoir plusieurs utilisateurs pour une seule identité). Un utilisateur peut désormais posséder plusieurs rôles, et peut passer de l’un à l’autre sans devoir se déconnecter. <a href="https://www.cremecrm.com/forum/showthread.php?tid=278">Voir ce lien pour plus de détails</a>.</p>
<p><img alt="Sélection d’un de ses rôles dans me menu principal" src="https://img.linuxfr.org/img/68747470733a2f2f696d672e6879626972642e6f72672f6372656d652f696d672f6372656d6532382f6372656d655f32385f46525f6d756c74695f726f6c65322e706e67/creme_28_FR_multi_role2.png" title="Source : https://img.hybird.org/creme/img/creme28/creme_28_FR_multi_role2.png"/></p>
<p>Les rôles peuvent désormais être désactivés. De manière générale, on essaie d’ajouter, au fur et à mesure des versions, la possibilité pour les différents objets que les utilisateurs peuvent supprimer de pouvoir d’abord passer par un état “désactivé”. Cela permet de tester un certain temps si un objet ne manque pas au final ; s’il y a un souci on peut revenir en arrière. C’est donc au tour des rôles d’avoir une telle fonctionnalité.</p>
<p>Les rôles gèrent maintenant les types de fiches qu’on peut lister, et 2 permissions spéciales peuvent être données : administration des utilisateurs &amp; des rôles (il fallait être super-utilisateur pour les administrer dans les versions précédentes).</p>
<h3 id="toc-Épinglage-de-fiche">Épinglage de fiche</h3>
<p>Vous pouvez désormais épingler les fiches auxquelles vous accédez souvent, pour aller dans leur vue détaillée.</p>
<p><img alt="Bouton d’épinglage dans l’entête d’une fiche" src="https://img.linuxfr.org/img/68747470733a2f2f696d672e6879626972642e6f72672f6372656d652f696d672f6372656d6532382f6372656d655f32385f46525f70696e312e706e67/creme_28_FR_pin1.png" title="Source : https://img.hybird.org/creme/img/creme28/creme_28_FR_pin1.png"/></p>
<p>Vous pouvez accéder aux dernières fiches épinglées dans l’entrée de menu « Accès rapide » ; cette entrée remplace l’entrée qui proposait uniquement les fiches visitées récemment, et propose ces dernières ainsi que les fiches épinglées :</p>
<p><img alt="Entrée « Accès rapide » dans le menu" src="https://img.linuxfr.org/img/68747470733a2f2f696d672e6879626972642e6f72672f6372656d652f696d672f6372656d6532382f6372656d655f32385f46525f70696e332e706e67/creme_28_FR_pin3.png" title="Source : https://img.hybird.org/creme/img/creme28/creme_28_FR_pin3.png"/></p>
<h3 id="toc-totaux-calculés-dans-les-vues-en-liste">Totaux calculés dans les vues en liste</h3>
<p>Certaines colonnes de vue en liste affichent désormais des totaux calculés sur toutes les fiches de cette liste :</p>
<ul>
<li>la somme et la moyenne des totaux (avec et sans TVA) des Factures/Devis/Avoirs/Bons de commande.</li>
<li>la somme et la moyenne des chiffres d’affaires estimé &amp; final des opportunités d’affaire.</li>
</ul>
<h3 id="toc-amélioration-des-champs-personnalisés">Amélioration des champs personnalisés</h3>
<p>Les champs personnalisés (les champs de fiches ajoutés par les utilisateurs) peuvent posséder :</p>
<p>– une description ; celle-ci est utilisée notamment dans les formulaires afin de donner plus de détails aux utilisateurs sur le sens dudit champ.<br/>
 – une valeur par défaut, utilisée à la création de nouvelles fiches ; <a href="https://www.cremecrm.com/forum/showthread.php?tid=281">voir ce lien pour plus de détails</a>.</p>
<h3 id="toc-quelques-autres-améliorations-notables">Quelques autres améliorations notables</h3>
<ul>
<li>L’éditeur de texte HTML (utilisé pour les corps HTML d’e-mail par exemple) a subi une grosse mise-à-jour (l’interface est bien plus légère et moderne maintenant), et est utilisé à plus d’endroits.</li>
<li>On peut désormais télécharger plusieurs Documents, Factures ou Devis en une fois sous forme d’archive <code>zip</code>.</li>
</ul>
<h2 id="toc-le-futur">Le futur</h2>
<p>La prochaine version devrait être la 3.0, et se concentrera sur une grosse revisite de l’interface graphique. À l’année prochaine !</p>
</div><div><a href="https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-8.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143282/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-8#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>GuieA_7,Benoît Sibaud,Ysabeau  🧶</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le lundi 18 mai</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-lundi-18-mai/3002" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-lundi-18-mai/3002</id>
        <updated>2026-05-07T14:27:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Le prochain meetup sur Lyon a lieu le lundi 18 mai à 19h.</p>
<p>Rendez-vous chez Lowit (métro Part-Dieu) où Emmanuel nous parlera de microcontrôleurs et de MicroPython !</p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-lundi-18-mai/3002/1" style="font-weight: bold; font-size: 1.1em;">Excursion dans le monde des microcontrôleurs</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">May 18, 2026 7:00 PM (Europe/Paris) → May 18, 2026 9:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://www.meetup.com/fr-fr/python-afpy-lyon/events/314642594/</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-lundi-18-mai/3002">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Configuration emacs « minimale » en 2026</title>
        <link href="https://discuss.afpy.org/t/configuration-emacs-minimale-en-2026/3001" />
        <id>https://discuss.afpy.org/t/configuration-emacs-minimale-en-2026/3001</id>
        <updated>2026-05-07T12:47:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>C’est la suite de mon sujet de 2021 : <a class="inline-onebox" href="https://discuss.afpy.org/t/emacs-aujourdhui-jessaye-lsp-mode/231">Emacs : aujourd'hui j'essaye lsp-mode</a>.</p>
<p>En 2026 je migre de <a href="https://github.com/pappasam/jedi-language-server/">jedi</a> qui n’est plus maintenu à <a href="https://github.com/zubanls/zuban">zuban</a>. J’en profite pour migrer de <code>lsp-mode</code> à <code>eglot</code> qui est devenu natif.</p>
<p>Déjà, à quoi ça ressemble :</p>
<p></p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/3/34b17f68d22f3c4066c739f7345bec6498f0c7d5.png" title="Capture d’écran du 2026-05-07 13-24-15"><img alt="Capture d’écran du 2026-05-07 13-24-15" height="418" src="https://discuss.afpy.org/uploads/default/optimized/2X/3/34b17f68d22f3c4066c739f7345bec6498f0c7d5_2_690x418.png" width="690"/></a></div><p></p>
<p>Le paquet Debian que j’utilise est <code>emacs-pgtk</code>.</p>
<p>Ensuite, la config « minimale » (72 lignes) :</p>
<pre><code class="lang-lisp">(require 'use-package)
(require 'package)
(package-initialize)

(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
                         ("melpa" . "https://melpa.org/packages/")))

(when (not package-archive-contents)
  (package-refresh-contents))

(use-package yasnippet
  :ensure t
  :config
  (yas-global-mode 1))

(use-package yasnippet-snippets
  :ensure t)

(use-package company
  :ensure t
  :hook
  (python-mode . company-mode))

(use-package envrc
  :ensure t
  :init (envrc-global-mode))

(use-package eglot
  :hook (python-mode . eglot-ensure)
  :config
  (add-to-list 'eglot-stay-out-of 'flymake)
  (add-to-list 'eglot-server-programs '((python-mode) . ("zuban" "server"))))

(use-package python
  :custom
  (python-indent-guess-indent-offset nil))

(use-package flycheck
  :ensure t
  :config
  (global-flycheck-mode t))

(use-package blacken
  :ensure t
  :commands (blacken-mode)
  :hook (python-mode . blacken-mode)
  :config
  (setq blacken-only-if-project-is-blackened t))

(use-package python-isort
  :ensure t
  :hook ((python-mode) . python-isort-on-save-mode)
  :config
  (setq python-isort-arguments '("--stdout" "--atomic" "-" "--profile=black")))

(use-package whitespace
  :diminish (whitespace-mode global-whitespace-mode whitespace-newline-mode)
  :hook ((python-mode) . whitespace-mode)
  :config
  (setq show-trailing-whitespace t)
  (setq whitespace-line-column 88)
  (setq whitespace-style '(face empty tabs lines-tail trailing)))

(use-package spacemacs-theme
  :ensure t
  :defer t
  :init
  (load-theme 'spacemacs-light t))

(global-font-lock-mode t)
(column-number-mode t)
(show-paren-mode t)
</code></pre>
<p>Le fichier se place dans <code>~/.emacs.d/init.el</code>. La première fois qu’emacs démarre il télécharge tous les paquets décrits dans la config, donc le premier démarrage est long, c’est normal.</p>
<p>Maintenant pour qu’eglot puisse trouver zuban, pour que flycheck puisse trouver pylint, et pour que blacken-mode puisse trouver black le mieux c’est … un venv !</p>
<p>Et pour que le venv du projet soit chargé automatiquement par emacs j’utilise <a href="https://github.com/direnv/direnv">direnv</a>, ça fait double usage : mes venv sont aussi activés automatiquement dans le shell !</p>
<p>Pour configurer <code>direnv</code> il faut un fichier <code>.envrc</code> à la racine du projet qui contient :</p>
<pre><code>VIRTUAL_ENV=.venv
layout python3
</code></pre>
<p>Si c’est votre première utilisation de <code>direnv</code> il faut rajouter <code>eval "$(direnv hook bash)"</code> dans <code>~/.bashrc</code>.<br/>
Il vous fera executer <code>direnv allow</code> pour l’autoriser à bosser, et hop, le venv est crée tout seul, et activé automatiquement par <code>bash</code> et <code>emacs</code>.</p>
<p>Faites-vous <a href="https://git.afpy.org/mdk/dotfiles/src/branch/main/.local/bin/venv">un alias ou une commande</a> nommé <code>venv</code> pour gagner du temps sur la création de ce <code>.envrc</code>.</p>
<p>Il faut installer deux-trois trucs dans le <code>venv</code> :</p>
<pre><code>pip install --upgrade zuban black mypy pylint
</code></pre>
<p>puis démarrer emacs :</p>
<pre><code>emacs test.py
</code></pre>
<p>Pour ceux qui n’ont jamais lancé <code>emacs</code> avant, tapez <code>Ctrl</code>-<code>h</code> puis <code>t</code>, ça vous ouvrira le tuto interactif.</p>
<p>Ohhh, et j’ai configuré <code>blacken-mode</code> pour ne passer <code>black</code> à la sauvegarde que s’il trouve <code>[tool.black]</code> dans <code>pyproject.toml</code>, ça m’évite d’avoir emacs qui réecrit des fichiers dans des projets qui n’utilisent pas <code>black</code>, c’est la ligne <code>blacken-only-if-project-is-blackened</code> dans la config.</p>
<p>Quelques raccourcis importants :</p>
<ul>
<li><code>M-.</code>  : c’est pour aller a la définition de quelque chose.</li>
<li><code>M-x eglot-rename</code> pour renommer une variable (et toutes ses occurrences).</li>
<li><code>C-c ! n</code> pour sauter a la prochaine erreur.</li>
</ul>
<p>Ma configuration complète est ici : <a href="https://git.afpy.org/mdk/dotfiles/src/branch/main/.emacs.d/init.el">https://git.afpy.org/mdk/dotfiles/src/branch/main/.emacs.d/init.el</a>, elle est plus longue : j’enlève les menus, le message d’accueil, la décoration de la fenêtre, j’ajoute du confort, et j’ai de la configuration C, rust, org-mode, je configure emacs en mode serveur (et j’utilise emacsclient), etc…</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/configuration-emacs-minimale-en-2026/3001">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>lsdisplay / lsgpu — lister écrans et GPUs depuis le terminal dans l&#39;esprit de lspci, lscpu, lsusb: v.0.1.0 appel à tests</title>
        <link href="https://linuxfr.org/users/geheme/journaux/lsdisplay-lsgpu-lister-ecrans-et-gpus-depuis-le-terminal-dans-l-esprit-de-lspci-lscpu-lsusb-v-0-1-0-appel-a-tests" />
        <id>https://linuxfr.org/users/geheme/journaux/lsdisplay-lsgpu-lister-ecrans-et-gpus-depuis-le-terminal-dans-l-esprit-de-lspci-lscpu-lsusb-v-0-1-0-appel-a-tests</id>
        <updated>2026-05-04T00:29:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 id="toc-le-problème">Le problème</h2>
<p>On a <code>lsusb</code>, <code>lspci</code>, <code>lscpu</code>… mais rien pour les écrans ou les GPUs.<br/>
Pour savoir quel écran est branché sur quelle sortie, c'est la danse du<br/>
<code>xrandr | grep connected</code>, <code>cat /sys/class/drm/card*/edid | edid-decode</code>,<br/>
<code>nvidia-smi</code>… </p>
<p>J'ai écrit deux outils pour régler ça.</p>
<h3 id="toc-lsdisplay">lsdisplay</h3>
<p>Liste les écrans connectés avec fabricant, modèle, numéro de série,<br/>
résolution, fréquence, diagonale, et dessine un schéma ASCII du layout :</p>
<pre><code class="text">$ lsdisplay

CONNECTED DISPLAYS
==================

  DP-4         1440x2560+0+0           27"  75Hz  Iiyama PL2792Q    DisplayPort  S/N:1152031921274   rot=left [PRIMARY]
  HDMI-A-2     1440x2560+1441+0        27"  75Hz  Iiyama PL2792Q    HDMI         S/N:1152032422031   rot=left
  HDMI-A-5     5376x3024+0+2561        65"  60Hz  Samsung QN800D    HDMI         S/N:94:e6:ba:dd:9a:7a

Total: 3 display(s) connected

LAYOUT
======

  +--------------+ +--------------+
  |              | |              |
  |     DP-4*    | |   HDMI-A-2   |
  |              | |              |
  +--------------+ +--------------+

  +------------------------------+
  |                              |
  |          HDMI-A-5            |
  |                              |
  +------------------------------+</code></pre>
<p>Fonctionnalités :</p>
<ul>
<li>Parse les EDID directement depuis <code>/sys/class/drm</code> (pas de dépendance externe)</li>
<li>Fonctionne sur X11 et Wayland (KDE, Sway, wlroots)</li>
<li>Mode <code>--json</code> pour le scripting</li>
<li>Mode <code>--scan</code> pour découvrir les Smart TV Samsung sur le réseau</li>
<li>Fichier d'overrides pour corriger les EDID buggés (Samsung, je te regarde…)</li>
<li>Python 3.6+, zéro dépendance</li>
</ul>
<h3 id="toc-lsgpu">lsgpu</h3>
<p>Liste les GPUs avec stats NVIDIA, mapping écran par sortie :</p>
<pre><code class="text">$ lsgpu

GRAPHICS CARDS
==============

  card0: NVIDIA GA107 [GeForce RTX 3050 6GB]
         Driver: nvidia | VRAM: 6 GB | GPU:0% MEM:2077/6144MB 37°C 16.7W
    ├─ DP-4: connected ← Iiyama PL2792Q 27"
    ├─ HDMI-A-2: connected ← Iiyama PL2792Q 27"


  card1: Intel Arrow Lake-S [Intel Graphics]
         Driver: i915
    ├─ HDMI-A-5: connected ← Samsung TQ65QN800DTXXC 65"

Total: 2 GPU(s), 3 output(s) connected</code></pre>
<p>Fonctionnalités :</p>
<ul>
<li>Stats NVIDIA (utilisation, température, puissance, mémoire)</li>
<li>Stats AMD via sysfs</li>
<li>Mode <code>--watch</code> avec sparklines en temps réel</li>
<li>Liste des processus utilisant le GPU</li>
<li>Python 3.6+, zéro dépendance Python</li>
</ul>
<h3 id="toc-installation">Installation</h3>
<pre><code class="bash">sudo cp lsdisplay.py /usr/local/bin/lsdisplay
sudo chmod +x /usr/local/bin/lsdisplay</code></pre>
<p>Paquet <code>.deb</code> disponible aussi. Un seul fichier Python, pas de pip, pas de venv.</p>
<h3 id="toc-appel-à-testeurs">Appel à testeurs</h3>
<p>C'est une v0.1.0 — testé sur ma config (GPU NVIDIA + Intel, KDE Wayland,<br/>
3 écrans dont 2 Samsung TV). J'aimerais des retours sur :</p>
<ul>
<li>Configs AMD (j'ai le code mais pas le matos pour tester)</li>
<li>Wayland hors KDE (Sway, GNOME, Hyprland)</li>
<li>Écrans avec EDID exotiques</li>
<li>Suggestions d'affichage ou de fonctionnalités</li>
</ul>
<h3 id="toc-liens">Liens</h3>
<ul>
<li><a href="https://github.com/AGuyMarc/lsdisplay">lsdisplay sur GitHub</a></li>
<li><a href="https://github.com/AGuyMarc/lsgpu">lsgpu sur GitHub</a></li>
</ul>
<p>Licence : GPL-2.0</p>
<div><a href="https://linuxfr.org/users/geheme/journaux/lsdisplay-lsgpu-lister-ecrans-et-gpus-depuis-le-terminal-dans-l-esprit-de-lspci-lscpu-lsusb-v-0-1-0-appel-a-tests.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143241/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/geheme/journaux/lsdisplay-lsgpu-lister-ecrans-et-gpus-depuis-le-terminal-dans-l-esprit-de-lspci-lscpu-lsusb-v-0-1-0-appel-a-tests#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>géhème</name>
        </author>
    </entry>
    <entry>
        <title>Fonctionnement de Jupyter Lab/Notebook</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/fonctionnement-de-jupyter-lab-notebook" />
        <id>https://linuxfr.org/forums/programmation-python/posts/fonctionnement-de-jupyter-lab-notebook</id>
        <updated>2026-04-22T15:11:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<h3 id="toc-contexte">Contexte:</h3>
<p>Je cherche une alternative à mathlab simulink pour la mise au point d'algorithmes de contrôle et la modélisation de systèmes.</p>
<p>Après quelques essais (scilab xcos, modelica, octave …), c'est python qui a retenu mon attention et en particulier les notebook Jupyter et la <a href="https://python-control.readthedocs.io">bibliothèque control</a>.</p>
<p>Ça fait quelques jours que je fais un essai sur la modélisation d'une régulation pour un générateur de courant mais certaines subtilités m'échappe.</p>
<p>En particulier, lorsque je veux modifier un paramètre dans une "cellule code" et la rejouer. Si cette dernière contient une courbe générer avec matplotlib, soit la courbe ne s'affiche pas, ou bien pas correctement, ou toutes les autres courbes s'en retrouve modifiées…</p>
<p>Matplotlib propose bien des <a href="https://matplotlib.org/stable/gallery/subplots_axes_and_figures/multiple_figs_demo.html">exemples d'utilisation</a>, mais comme mes essais, ils ne semblent fonctionner que si l'on exécute le "notebook" une seule fois.</p>
<h3 id="toc-question">Question:</h3>
<p>L'utilisation de Jupyter notebook est-elle réservée à la documentation final du processus et non aux essais ? Ou bien je passe à côté de quelque chose ?</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/fonctionnement-de-jupyter-lab-notebook.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143095/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/fonctionnement-de-jupyter-lab-notebook#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>uneTanche</name>
        </author>
    </entry>
    <entry>
        <title>Mise à jour Python et modules</title>
        <link href="https://discuss.afpy.org/t/mise-a-jour-python-et-modules/2998" />
        <id>https://discuss.afpy.org/t/mise-a-jour-python-et-modules/2998</id>
        <updated>2026-04-22T07:41:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>j’utilise Linux Mint et les mises à jour de Python sont automatiques.</p>
<p>Faut-il faire une mise à jour de la version de Python sous venv et comment ?</p>
<p>Pour les modules , quelle est la procédure de mise à jour ?</p>
<p>Merci d’avance</p>
<p><small>27 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/mise-a-jour-python-et-modules/2998">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommBL</name>
        </author>
    </entry>
    <entry>
        <title>Fusion de comptes</title>
        <link href="https://discuss.afpy.org/t/fusion-de-comptes/2997" />
        <id>https://discuss.afpy.org/t/fusion-de-comptes/2997</id>
        <updated>2026-04-22T07:37:32Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>suite à recréation d’un compte github, j’ai été obligé (?) de me recréer un compte sur votre site.</p>
<p>Serait-il possible de regrouper mon ancien compte mapomm??? avec mon nouveau compte mapommBL et ne laisser que mon compte mapommBL ?</p>
<p>Merci d’avance</p>
<p><small>7 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/fusion-de-comptes/2997">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommBL</name>
        </author>
    </entry>
    <entry>
        <title>The Slow Collapse of MkDocs</title>
        <link href="https://linuxfr.org/users/m5oul/liens/the-slow-collapse-of-mkdocs" />
        <id>https://linuxfr.org/users/m5oul/liens/the-slow-collapse-of-mkdocs</id>
        <updated>2026-04-20T20:50:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://fpgmaas.com/blog/collapse-of-mkdocs/">https://fpgmaas.com/blog/collapse-of-mkdocs/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/143069/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/m5oul/liens/the-slow-collapse-of-mkdocs#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>M5oul</name>
        </author>
    </entry>
    <entry>
        <title>[PYTHON] Besoin d&#39;aide sur un exercice</title>
        <link href="https://discuss.afpy.org/t/python-besoin-daide-sur-un-exercice/2992" />
        <id>https://discuss.afpy.org/t/python-besoin-daide-sur-un-exercice/2992</id>
        <updated>2026-04-17T09:24:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Je débute en programmation et je me suis heurté a une incompréhension sur la correction d’un exercice :</p>
<pre><code class="lang-python">nombres = input("tapez votre suite de nombre séparé par des virgule")

liste = nombres.split(",")

liste_entier = []

for nombre in liste:

    nombre_entier = int(nombre)

    liste_entier.append(nombre_entier)

print("liste: ", liste_entier)

somme = 0

for nombre in liste_entier:

    somme += nombre

print("somme : ", somme)

moyenne = somme / len(liste_entier)

print("moyenne: ", moyenne)

nombre_superieur_moyenne = 0

for nombre in liste_entier:

    if nombre &gt; moyenne:

        nombre_superieur_moyenne += 1

print("nombre suprieur: ", nombre_superieur_moyenne)
</code></pre>
<p>Ca peut paraitre évident  pour certain mais je ne comprend pas pourquoi, à la ligne 4 ( for nombre in liste:) il y a ce “nombre” qui sort de nul part  , alors que ma variable plus haut est “nombres”. J’ai cherché, pensant que “nombre” était peut être déjà connu par le logiciel, mais je ne trouve rien a ce sujet.</p>
<p>Je n’arrive pas à passer outre cette incompréhension, et cella me retarde dans mon apprentissage, si une personne avais l’amabilité de prendre un petit peu de son temps pour m’expliquer cela j’en serait comblé. Merci d’avance et je vous souhaite une agréable journée</p>
<p><small>6 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/python-besoin-daide-sur-un-exercice/2992">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>konzum</name>
        </author>
    </entry>
    <entry>
        <title>Retours d&#39;expérience de frameworks web et d&#39;orchestration de workflows - lundi 27 avril 2026</title>
        <link href="https://discuss.afpy.org/t/retours-dexperience-de-frameworks-web-et-dorchestration-de-workflows-lundi-27-avril-2026/2991" />
        <id>https://discuss.afpy.org/t/retours-dexperience-de-frameworks-web-et-dorchestration-de-workflows-lundi-27-avril-2026/2991</id>
        <updated>2026-04-16T08:29:35Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <ul>
<li><strong>Django Ninja : votre API nette et sans bavure ?</strong> - par Quentin Caron (<a href="https://www.linkedin.com/in/qcaron" rel="noopener nofollow ugc">profil LinkedIn</a>), lead dev Python et expert technique chez Néosoft</li>
</ul>
<p>Vous aimez Django mais vous avez préféré un autre framework pour écrire votre API ? Ce retour d’expérience sur Django Ninja vous fera peut-être changer d’avis. Après un tour d’horizon des frameworks web API Python permettant de planter le décor, découvrez les caractéristiques du framework, les difficultés rencontrées en 10 semaines d’utilisation et les contournements possibles pour devenir un véritable ninja des APIs.</p>
<ul>
<li><strong>Comparaison de 4 orchestrateurs de workflows open-source : airflow, argo, <a href="http://temporal.io," rel="noopener nofollow ugc">temporal.io,</a> windmill</strong> par Jesshuan Diné (<a href="https://www.linkedin.com/in/ACoAAAviFWwBnUYqVSms_J2uPMcisyTZVBM7VpI/?lipi=urn%3Ali%3Apage%3Ad_flagship3_notifications%3Bv9Uq6y1pSCSJa5H1aFLuNw%3D%3D" rel="noopener nofollow ugc">profil LinkedIn</a>), ingénieur data et IA chez Crédit Mutuel Arkéa</li>
</ul>
<p>Nos métiers intègrent de plus en plus de traitements d’ingestion et de remaniement de la donnée. J’ai eu besoin de faire un benchmark pour comparer différents frameworks d’orchestration open-source qui répondaient à mes besoins. Après une brève présentation des candidats et de leur différence de paradigmes, je vous présenterai la méthodologie que j’ai suivi pour les comparer (notamment concernant la performance de l’infrastructure) et les résultats.<br/>
Au menu :</p>
<ul>
<li>une infra kubernetes</li>
<li>des workflows CPU-intensifs</li>
<li>une stack d’observabilité</li>
</ul>
<p>Merci à Néosoft Rennes pour l’accueil du meetup <img alt=":folded_hands:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/folded_hands.png?v=15" title=":folded_hands:" width="20"/></p>
<p>Publication à relayer sur les réseaux si vous le souhaitez :</p>
<ul>
<li>
<p>LinkedIn : <a href="https://www.linkedin.com/feed/update/urn:li:share:7448361686618554368/" rel="noopener nofollow ugc">https://www.linkedin.com/feed/update/urn:li:share:7448361686618554368/</a></p>
</li>
<li>
<p>Mastodon : <a href="https://social.breizhcamp.org/@pythonrennes/116380639349165036" rel="noopener nofollow ugc">https://social.breizhcamp.org/@pythonrennes/116380639349165036</a></p>
</li>
<li>
<p>BlueSky : <a href="https://bsky.app/profile/pythonrennes.bsky.social/post/3mjflfzri522f" rel="noopener nofollow ugc">https://bsky.app/profile/pythonrennes.bsky.social/post/3mjflfzri522f</a></p>
</li>
</ul>
<p>Inscription gratuite mais nécessaire sur :</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon" height="48" src="https://secure.meetupstatic.com/next/images/favicon.ico" width="48"/>
<a href="https://www.meetup.com/python-rennes/events/314213069/" rel="noopener nofollow ugc" target="_blank">Meetup</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img alt="" class="thumbnail" height="338" src="https://secure.meetupstatic.com/photos/event/b/6/5/7/600_533626679.jpeg" width="600"/></div>
<h3><a href="https://www.meetup.com/python-rennes/events/314213069/" rel="noopener nofollow ugc" target="_blank">Retours d'expérience de frameworks web et d'orchestration de workflows, lun....</a></h3>
<p>Une fois n'est pas coutume, on se penche sur des frameworks grâce à 2 retours d'expérience :

* **Quentin Caron** nous parlera de [Django Ninja](https://django-ninja.dev/)</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/retours-dexperience-de-frameworks-web-et-dorchestration-de-workflows-lundi-27-avril-2026/2991">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>luc_sorel-giffo</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le jeudi 23 avril</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-jeudi-23-avril/2989" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-jeudi-23-avril/2989</id>
        <updated>2026-04-13T13:18:14Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Le prochaine meetup à Lyon a lieu le jeudi 23 avril. Rendez-vous à 19h à la Cordée Jean Macé (métro Jean Macé / Saxe-Gambetta) !</p>
<p>Éden et Rémi parleront de musique avec Sardine <img alt=":musical_notes:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/musical_notes.png?v=15" title=":musical_notes:" width="20"/> <img alt=":fish:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/fish.png?v=15" title=":fish:" width="20"/></p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-jeudi-23-avril/2989/1" style="font-weight: bold; font-size: 1.1em;">Sardine : entrez dans le monde de la musique et du live coding avec Python</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">April 23, 2026 7:00 PM (Europe/Paris) → April 23, 2026 9:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://www.meetup.com/fr-fr/python-afpy-lyon/events/314118158/</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-jeudi-23-avril/2989">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>markitdown : {pdf,docx,xslx,audio,pptx,outlook,..} &gt; .md  Convertir en Markdown avec soin pour la structure de texte</title>
        <link href="https://linuxfr.org/users/bubar/liens/markitdown-pdf-docx-xslx-audio-pptx-outlook-md-convertir-en-markdown-avec-soin-pour-la-structure-de-texte" />
        <id>https://linuxfr.org/users/bubar/liens/markitdown-pdf-docx-xslx-audio-pptx-outlook-md-convertir-en-markdown-avec-soin-pour-la-structure-de-texte</id>
        <updated>2026-04-12T20:07:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://github.com/microsoft/markitdown">https://github.com/microsoft/markitdown</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142969/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/bubar/liens/markitdown-pdf-docx-xslx-audio-pptx-outlook-md-convertir-en-markdown-avec-soin-pour-la-structure-de-texte#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>bubar🦥</name>
        </author>
    </entry>
    <entry>
        <title>rajout d&#39;un défilement vertical</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/rajout-d-un-defilement-vertical" />
        <id>https://linuxfr.org/forums/programmation-python/posts/rajout-d-un-defilement-vertical</id>
        <updated>2026-04-09T08:28:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://framagit.org/vev/elo-lvgsports">https://framagit.org/vev/elo-lvgsports</a><br/>
Il y a beaucoup de problèmes dans mon code; le rafraîchissement des scores par exemple.</p>
<p>Mais celui qui me limite le plus dans son usage c'est que je ne peux pas tout voir lorsque le nombre d'équipes/joueurs devient élevé.<br/>
Quelqu'un saurait faire scroller l'ensemble de la fenêtre verticalement? Je suppose que ce n'est pas sorcier mais je n'y arrive pas…</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/rajout-d-un-defilement-vertical.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142922/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/rajout-d-un-defilement-vertical#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>vev</name>
        </author>
    </entry>
    <entry>
        <title>Quand utiliser Docker en production ?</title>
        <link href="https://bearstech.com/societe/blog/quand-utiliser-docker-en-production" />
        <id>https://bearstech.com/societe/blog/quand-utiliser-docker-en-production</id>
        <updated>2026-04-03T13:48:32Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris - Meetup Django le 16 avril</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-16-avril/2982" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-django-le-16-avril/2982</id>
        <updated>2026-04-03T13:28:48Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Meetup Django le <strong>16 avril 2026</strong> dans les locaux de <strong>Zenika</strong>, 53 Rue de Châteaudun, <strong>Paris</strong>.</p>
<p>L’occasion de se retrouver et d’en apprendre plus sur:</p>
<ul>
<li><strong>Nous voulons toujours des chevaux plus rapides</strong>, Darko Stankozski (Français)</li>
<li><strong>Vous n’étiez pas prêts pour les Design Systems</strong>, Matthias Dugué Cercy (Français)</li>
</ul>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-16-avril/2982/1" style="font-weight: bold; font-size: 1.1em;">Django Paris Meetup</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">April 16, 2026 6:30 PM (Europe/Paris) → April 16, 2026 9:30 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">53 Rue de Châteaudun</td>
</tr>
</tbody></table>
<p>Rappel des informations de l’événement sur <a href="https://www.meetup.com/fr-fr/django-paris/events/314095213/?slug=django-paris&amp;eventId=314095213" rel="noopener nofollow ugc">meetup.com</a>.</p>
<p>Tres bonne journée à toute/s !</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-16-avril/2982">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>sabderemane</name>
        </author>
    </entry>
    <entry>
        <title>Rivalcfg v4.17.0 released with Rival 5 and Prime+ support</title>
        <link href="https://linuxfr.org/users/flozz/liens/rivalcfg-v4-17-0-released-with-rival-5-and-prime-support" />
        <id>https://linuxfr.org/users/flozz/liens/rivalcfg-v4-17-0-released-with-rival-5-and-prime-support</id>
        <updated>2026-04-03T13:08:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://rivalcfg.flozz.org/news/release_v4.17.0/">https://rivalcfg.flozz.org/news/release_v4.17.0/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142873/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/flozz/liens/rivalcfg-v4-17-0-released-with-rival-5-and-prime-support#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>FLOZz</name>
        </author>
    </entry>
    <entry>
        <title>Anthropic réduit discrètement les allocations Claude sans prévenir :la grogne monte</title>
        <link href="https://www.olivierpons.fr/2026/03/30/anthropic-reduit-discretement-les-allocations-claude-sans-prevenir-la-grogne-monte/" />
        <id>https://www.olivierpons.fr/2026/03/30/anthropic-reduit-discretement-les-allocations-claude-sans-prevenir-la-grogne-monte/</id>
        <updated>2026-03-30T21:58:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Claude :la grogne monte</h1>
<p>Anthropic a opéré un ajustement en douceur de ses plafonds d’utilisation pour les abonnés Claude, réduisant mécaniquement la capacité de service durant les périodes de forte affluence afin d’équilibrer la demande avec ses ressources disponibles. L’annonce, pourtant significative, a été glissée le 26 mars 2026 par Thariq Shihipar, ingénieur au sein de l’équipe technique, via un simple post sur X — loin des canaux officiels de communication, ce qui a aiguisé l’irritation de nombreux clients.</p>
<h2>Ce qui change concrètement</h2>
<p>Durant les heures de pointe (de 5h à 11h heure du Pacifique, soit 13h à 19h GMT, en semaine), le coût en tokens de chaque session grimpe, ce qui signifie que l’allocation de cinq heures s’épuise plus vite que le temps réel d’activité. À l’inverse, les plafonds hebdomadaires demeurent inchangés — seule la répartition au fil des sept jours se modifie.<br/>
Qui trinque<br/>
Environ 7 % des utilisateurs heurteront désormais des limites qu’ils n’auraient pas atteintes auparavant. Les abonnés Pro sont les plus pénalisés. Les détenteurs de forfaits Max 20x s’en tirent largement, avec seulement 2 % de ce groupe concerné. Les abonnements touchés sont : Free, Pro (20 /mois),Max5x(100 /mois) et Max 20x (200 $/mois). Les clients API, facturés au token, échappent à cette mesure.</p>
<h2>Le contexte qui pèse</h2>
<p>Claude a engrangé des millions d’utilisateurs après que le contrat d’OpenAI avec le Pentagone a déclenché un boycott massif — 295 % de désinstallations de ChatGPT en une seule journée, 2,5 millions de participants au mouvement QuitGPT. Parallèlement, l’essor des fonctionnalités agentiques (vibe-coding, « computer use ») fait que les abonnés forfaitaires consomment bien plus de tokens qu’auparavant, tandis que les fournisseurs d’IA peinent à suivre la cadence.</p>
<h2>Les griefs légitimes</h2>
<p>Le manque de transparence suscite des critiques acerbes. De nombreux utilisateurs dénoncent l’absence de préavis, estimant que des changements substantiels sur les limites de service méritaient une annonce anticipée et officielle. La nouvelle a été discrètement publiée par un ingénieur sur les réseaux sociaux, plutôt que via un compte institutionnel ou le site web d’Anthropic.<br/>
Les faits rapportés ici sont corroborés par The Register, PCWorld, TechRadar, gHacks Tech News et plusieurs autres sources spécialisées.</p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>~False et ~True est déprécié, ou pas</title>
        <link href="https://discuss.afpy.org/t/false-et-true-est-deprecie-ou-pas/2978" />
        <id>https://discuss.afpy.org/t/false-et-true-est-deprecie-ou-pas/2978</id>
        <updated>2026-03-28T08:24:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>TL;DR :</p>
<pre><code class="lang-python">$ python3.14
Python 3.14.0 (main, Oct  8 2025, 07:31:52) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; ~False
&lt;python-input-0&gt;:1: DeprecationWarning: Bitwise inversion '~' on bool is deprecated and will be removed in Python 3.16. This returns the bitwise inversion of the underlying int object and is usually not what you expect from negating a bool. Use the 'not' operator for boolean negation or ~int(x) if you really want the bitwise inversion of the underlying int.
-1
</code></pre>
<p>Mais ça pourrait être autorisé à nouveau…</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon" height="32" src="https://static.lwn.net/images/favicon.png" width="32"/>
<a href="https://lwn.net/Articles/1059177/" rel="noopener" target="_blank">LWN.net</a>
</header>
<article class="onebox-body">
<h3><a href="https://lwn.net/Articles/1059177/" rel="noopener" target="_blank">The troubles with Boolean inversion in Python</a></h3>
<p>The Python bitwise-inversion (or complement) operator, '~', behaves pretty much as expected whe [...]</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/false-et-true-est-deprecie-ou-pas/2978">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>~False et ~True sont dépréciés, ou pas</title>
        <link href="https://discuss.afpy.org/t/false-et-true-sont-deprecies-ou-pas/2978" />
        <id>https://discuss.afpy.org/t/false-et-true-sont-deprecies-ou-pas/2978</id>
        <updated>2026-03-28T08:24:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>TL;DR :</p>
<pre><code class="lang-python">$ python3.14
Python 3.14.0 (main, Oct  8 2025, 07:31:52) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; ~False
&lt;python-input-0&gt;:1: DeprecationWarning: Bitwise inversion '~' on bool is deprecated and will be removed in Python 3.16. This returns the bitwise inversion of the underlying int object and is usually not what you expect from negating a bool. Use the 'not' operator for boolean negation or ~int(x) if you really want the bitwise inversion of the underlying int.
-1
</code></pre>
<p>Mais ça pourrait être autorisé à nouveau…</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon" height="32" src="https://static.lwn.net/images/favicon.png" width="32"/>
<a href="https://lwn.net/Articles/1059177/" rel="noopener" target="_blank">LWN.net</a>
</header>
<article class="onebox-body">
<h3><a href="https://lwn.net/Articles/1059177/" rel="noopener" target="_blank">The troubles with Boolean inversion in Python</a></h3>
<p>The Python bitwise-inversion (or complement) operator, '~', behaves pretty much as expected whe [...]</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/false-et-true-sont-deprecies-ou-pas/2978">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>The Story of Python&#39;s Lazy Imports: Why It Took Three Years and Two Attempts</title>
        <link href="https://linuxfr.org/users/thoasm/liens/the-story-of-python-s-lazy-imports-why-it-took-three-years-and-two-attempts" />
        <id>https://linuxfr.org/users/thoasm/liens/the-story-of-python-s-lazy-imports-why-it-took-three-years-and-two-attempts</id>
        <updated>2026-03-27T11:33:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://techlife.blog/posts/the-story-of-pythons-lazy-imports-why-it-took-three-years-and-two-attempts/">https://techlife.blog/posts/the-story-of-pythons-lazy-imports-why-it-took-three-years-and-two-attempts/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142773/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/thoasm/liens/the-story-of-python-s-lazy-imports-why-it-took-three-years-and-two-attempts#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>thoasm</name>
        </author>
    </entry>
    <entry>
        <title>PyCon Austria 2026</title>
        <link href="https://discuss.afpy.org/t/pycon-austria-2026/2976" />
        <id>https://discuss.afpy.org/t/pycon-austria-2026/2976</id>
        <updated>2026-03-27T09:28:32Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je relaie la communication de Horst JENS qui nous annonce que la PyCon Austria 2026, conférence internationale gratuite autour du langage de programmation Python, aura lieu les 19 et 20 avril prochains à l’université de sciences appliquées d’Eisenstadt en Autriche.<br/>
Les conférences et ateliers y seront donnés en anglais.</p>
<p>Les projets open-source et les groupes peuvent bénéficier d’un stand.</p>
<p>La conférence est gratuite mais l’inscription est recommandée :  <a href="https://pycon.at">https://pycon.at</a></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/pycon-austria-2026/2976">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>On a besoin de vous pour trouver un lieu pour la PyconFR 26</title>
        <link href="https://discuss.afpy.org/t/on-a-besoin-de-vous-pour-trouver-un-lieu-pour-la-pyconfr-26/2972" />
        <id>https://discuss.afpy.org/t/on-a-besoin-de-vous-pour-trouver-un-lieu-pour-la-pyconfr-26/2972</id>
        <updated>2026-03-25T21:50:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p></p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/0/0eb91e251cc88c69de847aa136c8a474e1489270.jpeg" title="On a besoin de vous !"><img alt="On a besoin de vous !" height="388" src="https://discuss.afpy.org/uploads/default/optimized/2X/0/0eb91e251cc88c69de847aa136c8a474e1489270_2_690x388.jpeg" width="690"/></a></div><p></p>
<p>Bonjour à toutes et tous,<br/>
L’association francophone Python (AFPy) organise chaque année la PyConFR, conférence qui réunit la communauté Python francophone sur plusieurs jours autour de présentations et ateliers.<br/>
C’est un événement entièrement gratuit pour les participant·e·s, financé par des sponsors mais aussi soutenu par des écoles / universités qui nous mettent à disposition leurs locaux à titre gracieux ou presque.</p>
<p>Nous faisons appel à vous car nous avons besoin d’aide : nous n’arrivons actuellement pas à trouver d’établissement qui pourrait nous accueillir pour l’édition 2026. Ainsi, nous sommes à la recherche de contacts au sein d’établissements aptes à nous accueillir pour convenir des modalités afin que la PyConFR 2026 puisse s’y tenir à l’automne prochain.</p>
<p>N’hésitez pas à nous contacter si vous avez la moindre piste et à diffuser ce message autour de vous, afin que la PyConFR 2026 ait lieu.<br/>
Merci beaucoup.</p>
<p>Vous pouvez aussi repartager cet appel sur vos réseaux :<br/>
Linkedin : <a class="inline-onebox" href="https://www.linkedin.com/company/26176072/admin/dashboard/">S’identifier sur LinkedIn | LinkedIn</a><br/>
Mastodon : <a class="inline-onebox" href="https://mamot.fr/deck/@AFPy/116291962225471731">AFPy : « 📣 L’AFPy a besoin de vous pour trouver un lieu po… » - Mamot - Le Mastodon de La Quadrature du Net</a><br/>
Bluesky : <a class="inline-onebox" href="https://bsky.app/profile/afpy.mamot.fr.ap.brid.gy/post/3mhw2aadmprq2">@afpy.mamot.fr.ap.brid.gy on Bluesky</a></p>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/on-a-besoin-de-vous-pour-trouver-un-lieu-pour-la-pyconfr-26/2972">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Melcore</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/116291972683779568" />
        <id>https://mamot.fr/@AFPy/116291972683779568</id>
        <updated>2026-03-25T21:38:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>🙋 🙋‍♀️ C’est pourquoi nous faisons appel à vous : nous sommes à la recherche de contacts au sein d’établissements pour entrer en lien et discuter des modalités pour organiser la PyConFR à l’automne prochain.</p><p>N’hésitez pas à nous contacter par mail à contact@pycon.fr si vous avez la moindre piste et à diffuser ce message autour de vous, afin que la PyConFR 2026 puisse avoir lieu.</p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/116291962225471731" />
        <id>https://mamot.fr/@AFPy/116291962225471731</id>
        <updated>2026-03-25T21:35:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                "On a besoin de vous pour trouver le prochain lieu de la PyconFR", sur une image dans une classe de la PyconFR 2025, avec le logo de l'AFPY.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>De retour de la game jam</title>
        <link href="https://linuxfr.org/users/small_duck/journaux/de-retour-de-la-game-jam" />
        <id>https://linuxfr.org/users/small_duck/journaux/de-retour-de-la-game-jam</id>
        <updated>2026-03-24T12:39:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://linuxfr.org/users/small_duck/journaux/juge-de-hackaton-2-2">L’expérience d'il y a deux ans m'avait plus</a>, j'ai donc re-signé pour une journée de mentorat à la game jam de l'école de mademoiselle fille (un hackaton orienté jeux vidéos, ouverts aux élèves de 11 à 17 ans). Tout comme il y a deux ans, j'ai trouvé des équipes de jeunes hyper motivés, avec de belles idées, et certainement un poil trop d'ambition par rapport à leurs moyens, mais ça fait partie du jeu.</p>
<p>J'ai donc vu un Balatro-light en Python avec des dessins extraordinaires, un jeu de plate-formes en Godot codé en 6 heures, avec sons, animations, et petits sprites de pizza à attraper, ou encore une course pour sauver des chatons robots dans un univers 3D avec Unity.</p>
<p>Pour me préparer, j'avais décidé de coder le même mini jeu 3 fois avec pyGame, Godot et Unity3D, et de voir ce qu'il en était. Bien m'en a pris, car cela m'a permis d'être à peu près au point quand on m'a demandé de l'aide. Je vous parle un peu des 3 approches, avec la nimage traditionnelle.</p>
<p><img alt="Capture d'écran d'un jeu de tir en vue de dessus" src="https://img.linuxfr.org/img/68747470733a2f2f746563686e6f747572746c652e6e65742f696d616765732f707973706963652e706e67/pyspice.png" title="Source : https://technoturtle.net/images/pyspice.png"/></p>
<h2 id="toc-pygame">pygame</h2>
<p>Ce que je voyais au début comme une simple couche Python au dessus de la SDL est en fait plutôt complet, et rudement facile à utiliser. En particulier, j´admire la fonction <code>pygame.sprite.groupcollide</code> qui permet de faire de la collision de sprite au pixel près. C'est propre, ça marche, en 200 lignes on peut faire quelque chose d'honorable.</p>
<h2 id="toc-godot">Godot</h2>
<p>Très pro et léché, Godot m'a surpris - Il est vraiment possible de faire de belles choses simplement, l'approche par scènes fonctionne très bien, et l'éditeur de GDScript est pratique, avec une auto-complétion particulièrement bien fichue. De plus, il n'a pas trop changé dernièrement, les infos et tutos que l'on glane à droite à gauche sont généralement à jour</p>
<h2 id="toc-unity3d">Unity3D</h2>
<p>C'est le mastodonte - C'est plus lourd, plus lent à démarrer, et il tente très vite de te convaincre d'obtenir, voire d'acheter, tout un tas de plug-ins et de prefabs.</p>
<p>Je trouve la partie code moins bien intégrée. En particulier, ce choix de ne pas fournir d'éditeur de texte et de laisser l'utilisateur avec son éditeur par défaut, si elle est certainement pratique pour les utilisateurs avancés, n'est absolument pas ce dont j'ai besoin en tant que codeur débonnaire et dilettante - Mon bon vieux Emacs me fait à peu près la coloration syntaxique et l'indentation, mais pour avoir un bel environnent C# intégré, il m'aurait fallu mettre bien plus d'efforts dans l'installation de language servers et autres.</p>
<p>En revanche, l'approche par composants que l'on ajoute à chaque nœud du graphe, et la manière de référencer les objets du jeu dans les scripts via du glisser déposer dans l'interface est particulièrement élégante à mon sens.</p>
<h2 id="toc-et-maintenant">Et maintenant ?</h2>
<p>Je tente de garder le cap, et mon mini-jeu a suffisamment intéressé la plus jeune pour qu'on décide elle et moi de construire quelque chose avec ses dessins et mon code. Alors j'hésite - Insister avec le Python, ce qui me sera certainement utile pour le boulot? Pousser avec Godot avec l'idée que ce sera plus pertinent pour des projets plus ambitieux ? Revenir à mes premières amours et tout faire en C++ + SDL ? Passer au Rust ?</p>
<div><a href="https://linuxfr.org/users/small_duck/journaux/de-retour-de-la-game-jam.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142745/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/small_duck/journaux/de-retour-de-la-game-jam#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>small_duck</name>
        </author>
    </entry>
    <entry>
        <title>Vos agents IA dépendent d’entreprises américaines, et ça devrait vous poser problème</title>
        <link href="https://linuxfr.org/users/jon1012/journaux/vos-agents-ia-dependent-d-entreprises-americaines-et-ca-devrait-vous-poser-probleme" />
        <id>https://linuxfr.org/users/jon1012/journaux/vos-agents-ia-dependent-d-entreprises-americaines-et-ca-devrait-vous-poser-probleme</id>
        <updated>2026-03-24T08:57:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Début 2026, Anthropic a suspendu des milliers de comptes pour utilisation de Claude avec des outils tiers. Pas des comptes piratés ou abusifs — des développeurs qui avaient branché leur abonnement Claude sur OpenClaw ou des outils similaires. Compte bloqué, sans avertissement, sans recours clair.</p>
<p>Quelques semaines plus tard, le créateur d'OpenClaw (145K étoiles GitHub, le framework d'agents IA le plus utilisé au monde) a été recruté par OpenAI. Le projet est toujours sur GitHub, mais personne ne sait vraiment ce que ça signifie pour la suite.</p>
<p>Je raconte ça parce que ça m'a poussé à sortir un projet sur lequel je travaillais depuis un moment.</p>
<p>Je suis développeur basé en France. Je travaille depuis plusieurs années sur <a href="https://aleph.im">Aleph Cloud</a>, un réseau de calcul décentralisé — des nœuds indépendants qui fournissent de la puissance de calcul sans passer par AWS, GCP ou Azure. Quand j'ai vu les suspensions Anthropic et le rachat OpenClaw, la question que je me posais déjà est devenue urgente : est-ce qu'on peut faire tourner des agents IA sur une infrastructure que personne ne contrôle seul ?</p>
<p>La réponse est oui, et c'est ce que fait <a href="https://liberclaw.ai/fr">LiberClaw</a>.</p>
<p><strong>Comment ça marche concrètement</strong></p>
<p>Chaque agent tourne dans sa propre VM sur un nœud Aleph Cloud (CRN). Pas un conteneur partagé — une vraie machine virtuelle avec son système de fichiers et ses processus isolés. L'agent est un programme Python qui a accès à un ensemble d'outils : lecture/écriture de fichiers, navigation web, exécution de commandes shell, appels API. On décrit ce qu'il doit faire dans un fichier SKILL.md (un format texte compatible avec celui d'OpenClaw, donc si vous en avez déjà écrit, ça marche directement).</p>
<p>L'inférence passe par <a href="https://libertai.io">LibertAI</a>, qui fait tourner des modèles ouverts (Qwen3.5 35b-a3n, 27b et 122b-a10b selon les besoins…). Pas de clé API OpenAI. Pas de clé API Anthropic. L'agent utilise des modèles libres, point (et ils sont, pour ces cas d'usage aussi efficaces que les modèles anthropic/openai).</p>
<p>Côté sécurité, on a essayé de ne pas faire n'importe quoi :</p>
<ul>
<li>Les secrets de chaque agent sont chiffrés avec Fernet, une clé unique par agent. Personne d'autre que l'agent n'a accès à ses credentials.</li>
<li>L'authentification utilise des JWT avec rotation : access token de 15 minutes, refresh token de 30 jours. Pas de token permanent qui traîne.</li>
<li>Les commandes bash passent par des filtres regex avant exécution. L'agent ne peut pas faire <code>rm -rf /</code> ou exfiltrer des données vers l'extérieur sans passer les gardes.</li>
</ul>
<p>Je précise ça parce que l'écosystème OpenClaw a eu des problèmes réels sur ce plan : des instances exposées sans authentification sur Internet, des skills malveillants qui pouvaient exécuter du code arbitraire. On a construit LiberClaw en ayant ces cas en tête.</p>
<p>Après, c'est votre agent… donc si vous lui demandez quelque chose de bête, ce n'est pas infaillible et il le fera. C'est votre VM et vous êtes seul dessus.</p>
<p><strong>Pourquoi pas juste un VPS ?</strong></p>
<p>C'est la question évidente, et elle est légitime. Pourquoi se compliquer la vie avec de l'infrastructure décentralisée quand on peut louer un VPS à 5€/mois ?</p>
<p>Parce que le VPS, c'est OVH, Hetzner, ou AWS. Et OVH peut décider de fermer votre compte. AWS peut décider que votre usage viole ses conditions. On est en train de construire des outils qui tournent 24h/24, qui prennent des décisions, qui interagissent avec des APIs — et tout ça repose sur la bonne volonté d'un hébergeur.</p>
<p>Sur Aleph Cloud, les nœuds sont indépendants. Il n'y a pas d'interrupteur central. Personne ne peut décider unilatéralement d'éteindre votre agent. C'est le même principe que ce qui rend le réseau intéressant pour d'autres usages, mais appliqué aux agents IA.</p>
<p>Pour ceux qui suivent les discussions sur la souveraineté numérique en France (et vu le journal récent sur JemaOS, je sais que vous êtes quelques-uns), c'est un enjeu concret : vos agents IA ne dépendent pas d'une entreprise américaine pour fonctionner.</p>
<p><strong>État actuel</strong></p>
<p>La plateforme est en production. Plus de 99 agents tournent en ce moment: des agents de revue de code, des assistants de recherche, des agents de monitoring. L'interface est disponible en 11 langues dont le français (pas juste un Google Translate, les pages sont réellement localisées). Le tier gratuit donne 2 agents (et suffisamment de crédits d'inférence pour commencer à s'amuser).</p>
<p>Le code des agents est sur GitHub : <a href="https://github.com/Libertai/liberclaw-agent">github.com/Libertai/liberclaw-agent</a>. Si il y a des demandes pour le code de la plateforme web qui lance les agents, je peux la libérer aussi.</p>
<ul>
<li>Landing : <a href="https://liberclaw.ai/fr">liberclaw.ai/fr</a>
</li>
<li>App : <a href="https://app.liberclaw.ai">app.liberclaw.ai</a>
</li>
</ul>
<p>Si vous avez des questions sur l'architecture, les choix techniques ou si vous voulez juste me dire que c'est nul, je suis dans les commentaires.</p>
<div><a href="https://linuxfr.org/users/jon1012/journaux/vos-agents-ia-dependent-d-entreprises-americaines-et-ca-devrait-vous-poser-probleme.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142741/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jon1012/journaux/vos-agents-ia-dependent-d-entreprises-americaines-et-ca-devrait-vous-poser-probleme#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Jonathan Schemoul</name>
        </author>
    </entry>
    <entry>
        <title>Opportunité de stage : 2 stages proposés par Algoo pour travailler sur Tracim (python/JS/React) et sur un outil interne (python/Django/APIs)</title>
        <link href="https://linuxfr.org/users/lebouquetin/liens/opportunite-de-stage-2-stages-proposes-par-algoo-pour-travailler-sur-tracim-python-js-react-et-sur-un-outil-interne-python-django-apis" />
        <id>https://linuxfr.org/users/lebouquetin/liens/opportunite-de-stage-2-stages-proposes-par-algoo-pour-travailler-sur-tracim-python-js-react-et-sur-un-outil-interne-python-django-apis</id>
        <updated>2026-03-23T10:10:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://fosstodon.org/@Lebouquetin/116277922664714029">https://fosstodon.org/@Lebouquetin/116277922664714029</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142733/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/lebouquetin/liens/opportunite-de-stage-2-stages-proposes-par-algoo-pour-travailler-sur-tracim-python-js-react-et-sur-un-outil-interne-python-django-apis#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>LeBouquetin</name>
        </author>
    </entry>
    <entry>
        <title>Django : privilégier contributions humaines aux contributions générées par LLM</title>
        <link href="https://www.better-simple.com/django/2026/03/16/give-django-your-time-and-money/" />
        <id>https://www.better-simple.com/django/2026/03/16/give-django-your-time-and-money/</id>
        <updated>2026-03-20T16:40:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>L’usage excessif des LLM pour contribuer à Django pose problème : les mainteneurs ont du mal à évaluer si le contributeur comprend réellement le code proposé. L’article explique pourquoi la communauté Django privilégie l’authenticité et la compréhension réelle plutôt que des PR générées par IA. Des recommandations sont données pour utiliser les LLM comme outil complémentaire sans masquer sa compréhension du sujet.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/48272-django-privilegier-contributions-humaines-aux-cont#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/48272-django-privilegier-contributions-humaines-aux-cont">Django : privilégier contributions humaines aux contributions générées par LLM</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Recommendations de blogs</title>
        <link href="https://discuss.afpy.org/t/recommendations-de-blogs/2965" />
        <id>https://discuss.afpy.org/t/recommendations-de-blogs/2965</id>
        <updated>2026-03-20T09:53:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello!</p>
<p>Je me mets de plus en plus à lire des articles de blogs et je trouve ça passionnant, cf la discussion sur astral.sh racheté par OpenAI qui m’a fait découvrir le blog de <a href="https://simonwillison.net/" rel="noopener nofollow ugc">https://simonwillison.net/</a> auquel je me suis abonné immédiatement <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<p>Avez vous des recommandations de bon blogs (idéalement auxquels je peux m’abonner par mail), principalement python mais sinon tech en général, software, etc…</p>
<p>À vot’ bon cœur m’sieur dames</p>
<p><small>7 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/recommendations-de-blogs/2965">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>seluj78</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;hiver 2026</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2026" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2026</id>
        <updated>2026-03-19T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Mécénat</h1>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h1>Contributions</h1>
<h2>Il y a bien longtemps dans Python</h2>
<p>Une <a href="https://github.com/python/cpython/pull/4770">Pull Request</a> à <a href="https://www.python.org/">cpython</a> ajoutant un gestionnaire de contexte à <a href="https://docs.python.org/3/library/mailbox.html#mailbox.Mailbox">Mailbox</a> a été intégrée après une longue période d'inactivité. Elle datait de 2017, ce qui en faisait la 27ième plus vieille PR ouverte sur cpython.</p>
<h2><a href="https://pygments.org/">Pygments</a></h2>
<p><em>Bibliothèque Python de coloration syntaxique</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/3052">Amélioration de l'analyse des architectures dans le lexeur 'Debian control'</a></li>
</ul>
<h2><a href="https://debian.org/">Documentation Debian</a></h2>
<ul>
<li>Document de référence pour les développeurs Debian : <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1128883">Remplacement du format de fichier sources.list par debian.sources</a></li>
<li>Notes de publication : <a href="https://salsa.debian.org/ddp-team/release-notes/-/merge_requests/340">remplacements des chemins de signatures de paquets de <em>.gpg à </em>.pgp</a></li>
</ul>
<h2><a href="https://github.com/authlib/authlib">authlib</a></h2>
<p><em>La bibliothèque Python ultime pour construire des clients et serveurs OAuth et OpenID Connect. JWS, JWE, JWK, JWA, JWT inclus.</em></p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/850">Support de Python 3.10 à 3.14</a></li>
<li><a href="https://github.com/authlib/authlib/pull/853">Permettre la composition de AuthorizationServerMetadata</a></li>
<li><a href="https://github.com/authlib/authlib/pull/854">Correction du comportement de <code>expires_at</code> quand sa valeur est 0</a></li>
<li><a href="https://github.com/authlib/authlib/pull/855">Rendre les parenthèses de require_oauth optionnelles</a></li>
<li><a href="https://github.com/authlib/authlib/pull/864">Implémentation de la contre-mesure de rétrogradation PKCE rfc9700</a></li>
<li><a href="https://github.com/authlib/authlib/pull/865">Accepter l'URL de l'émetteur comme audience valide</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Logiciel léger de gestion des identités et des autorisations</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/322">Correction de l'upload d'avatar</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/323">Correction de l'autofocus des champs HTML</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/324">Ajout d'une page « authentification » dans la section profil utilisateur</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/325">Propriétaires de clients</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/327">Support CORS pour les endpoints OIDC et SCIM</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/329">Correction des problèmes CSP de Fomantic</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/330">Forcer auth-playground à utiliser le domaine client.localhost</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/332">Correction de la réinitialisation des champs par HTMX</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/333">Corrections de sécurité mineures et recommandations</a></li>
</ul>
<h2><a href="https://github.com/corydolphin/flask-cors">flask-cors</a></h2>
<p><em>Support du partage de ressources entre origines (CORS) pour Flask</em></p>
<ul>
<li><a href="https://github.com/corydolphin/flask-cors/pull/401">Support des origines <em>callable</em> pour la validation dynamique</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-cli">scim2-cli</a></h2>
<p><em>CLI de développement d'applications SCIM</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-cli/pull/23">Implémentation d'un environnement tox pyinstaller</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Construisez pythoniquement des requêtes SCIM et analysez les réponses SCIM</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/36">Rendre le type de contenu optionnel pour les statuts 204</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/38">Les exceptions SCIM fournissent des objets d'erreur</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/40">Utilisation des classes d'exception de scim2-models</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/44">Correction du typage du client asynchrone</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/115">Demander un attribut donné inclut ses sous-attributs</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/117">Refactorisation de la gestion des chemins</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/118">Les schémas de ressources et d'extensions doivent être définis dans la classvar <code>__schema__</code></a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/119">Refonte des erreurs et exceptions</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/120">Auto-exclusion de l'attribut primaire</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/121">Refonte des références</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/122">Implémentation de SCIMException.from_error</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/126">Correction de <code>model_json_schema</code> pour Reference et Path</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/129">Correction des errata RFC6743</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-server">scim2-server</a></h2>
<p><em>Prototype léger de serveur SCIM2</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-server/pull/16">Utilisation des exceptions natives de scim2-models</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>Vérificateur de conformité aux RFC SCIM</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/45">Utilisation de la gestion native des chemins de scim2-models</a></li>
</ul>
<h2><a href="https://github.com/Pylons/webtest">webtest</a></h2>
<p><em>Enveloppe n'importe quelle application WSGI et facilite l'envoi de requêtes de test à cette application, sans démarrer de serveur HTTP.</em></p>
<ul>
<li><a href="https://github.com/Pylons/webtest/pull/275">Migration du projet vers uv</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/wtforms">wtforms</a></h2>
<p><em>Une bibliothèque flexible de validation et de rendu de formulaires pour Python.</em></p>
<ul>
<li><a href="https://github.com/pallets-eco/wtforms/pull/883">Support des versions de Python de 3.10 à 3.14</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Winter 2026 FOSS contributions by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2026" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2026</id>
        <updated>2026-03-19T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Sponsoring</h1>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h1>Contributions</h1>
<h2>A long time ago in Python</h2>
<p>A <a href="https://github.com/python/cpython/pull/4770">Pull Request</a> to <a href="https://www.python.org/">cpython</a> adding a context manager to <a href="https://docs.python.org/3/library/mailbox.html#mailbox.Mailbox">Mailbox</a> has been merged after a long period of inactivity. It was created in 2017 and was the 27th oldest opened PR for cpython.</p>
<h2><a href="https://pygments.org/">Pygments</a></h2>
<p><em>Pygments is a generic syntax highlighter written in Python</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/3052">Improve architecture parsing in 'Debian control' lexer</a></li>
</ul>
<h2><a href="https://debian.org/">Debian Documentation</a></h2>
<ul>
<li>Reference for Debian developers: <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1128883">Replace sources.list by debian.sources file format</a></li>
<li>Release notes: <a href="https://salsa.debian.org/ddp-team/release-notes/-/merge_requests/340">Replace .gpg paths for package signatures by .pgp ones</a></li>
</ul>
<h2><a href="https://github.com/authlib/authlib">authlib</a></h2>
<p><em>The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS, JWE, JWK, JWA, JWT included.</em></p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/850">Support from Python 3.10 to 3.14</a></li>
<li><a href="https://github.com/authlib/authlib/pull/853">Allow composition of AuthorizationServerMetadata</a></li>
<li><a href="https://github.com/authlib/authlib/pull/854">Fix <code>expires_at</code> behavior when its value is 0</a></li>
<li><a href="https://github.com/authlib/authlib/pull/855">Make require_oauth parenthesis optional</a></li>
<li><a href="https://github.com/authlib/authlib/pull/864">Implement rfc9700 PKCE downgrade countermeasure</a></li>
<li><a href="https://github.com/authlib/authlib/pull/865">Accept the issuer URL as a valid audience</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/322">Fix avatar upload</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/323">Fix HTML field autofocus</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/324">Add an 'authentication' page in user profile section</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/325">Client owners</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/327">CORS support for OIDC and SCIM endpoints</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/329">Fix Fomantic CSP issues</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/330">Force auth-playground to use the client.localhost domain</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/332">Fix HTMX resetting inputs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/333">Minor security fixes and recommandations</a></li>
</ul>
<h2><a href="https://github.com/corydolphin/flask-cors">flask-cors</a></h2>
<p>*Cross Origin Resource Sharing ( CORS ) support for Flask *</p>
<ul>
<li><a href="https://github.com/corydolphin/flask-cors/pull/401">Support callable origins for dynamic validation</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-cli">scim2-cli</a></h2>
<p><em>SCIM application development CLI</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-cli/pull/23">Implement a pyinstaller tox env</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Pythonically build SCIM requests and parse SCIM responses</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/36">Make content type optional for 204 statuses</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/38">SCIM Exceptions provide errors objects</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/40">Use scim2-models exception classes</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/44">Fix async client typing</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/115">Requesting a given attribute includes its sub-attributes</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/117">Refactor path management</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/118">Resource and extensions schemas must be defined in the <code>__schema__</code> classvar</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/119">Errors and exceptions overhaul</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/120">Primary attribute auto-exclusion</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/121">Reference overhaul</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/122">Implement SCIMException.from_error</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/126">Fix <code>model_json_schema</code> for Reference and Path</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/129">Fix RFC6743 erratas</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-server">scim2-server</a></h2>
<p><em>Lightweight SCIM2 server prototype</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-server/pull/16">Use scim2-models native exceptions</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>SCIM RFCs server compliance checker</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/45">Use scim2-models native path management</a></li>
</ul>
<h2><a href="https://github.com/Pylons/webtest">webtest</a></h2>
<p><em>Wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.</em></p>
<ul>
<li><a href="https://github.com/Pylons/webtest/pull/275">Migrate the project to uv</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/wtforms">wtforms</a></h2>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/pallets-eco/wtforms/pull/883">Support Python versions from 3.10 to 3.14</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Astral.sh (ruff, uv, ty, pyx) vient d&#39;être rachetée par OpenAI - qu&#39;en pensez-vous ?</title>
        <link href="https://discuss.afpy.org/t/astral-sh-ruff-uv-ty-pyx-vient-detre-rachetee-par-openai-quen-pensez-vous/2963" />
        <id>https://discuss.afpy.org/t/astral-sh-ruff-uv-ty-pyx-vient-detre-rachetee-par-openai-quen-pensez-vous/2963</id>
        <updated>2026-03-19T21:28:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello</p>
<p>Astral.sh, l’entreprise qui édite (en rust) différents outils open-source pour l’écosystème Python, a annoncé sur son blog aujourd’hui avoir été rachetée par OpenAI : <a class="inline-onebox" href="https://astral.sh/blog/openai" rel="noopener nofollow ugc">Astral to join OpenAI</a> .</p>
<p>Les outils en question :</p>
<ul>
<li>ruff : linter et formateur de code</li>
<li>uv : gestionnaire de dépendances</li>
<li>ty : vérification statique de typage</li>
<li>pyx : une alternative à PyPI pour mettre à disposition des packages Python</li>
</ul>
<p>Je ne sais pas quelle place occupaient ces outils dans vos projets perso ou pro. J’avoue que j’appréciais une certaine indépendance de cet écosystème d’outils vis-à-vis de ceux de l’IA générative.</p>
<p>Comment vivez-vous ce changement de gouvernance ? Quelles sont les conséquences pour vos choix d’outillage et vos habitudes ?</p>
<p>Belle journée<br/>
Sympathicamicalement, Luc</p>
<p>PS : c’est le premier sujet que je lance sur ce forum de discussion. S’il est inapproprié, n’hésitez pas à me le dire.</p>
<p><small>8 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/astral-sh-ruff-uv-ty-pyx-vient-detre-rachetee-par-openai-quen-pensez-vous/2963">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>luc_sorel-giffo</name>
        </author>
    </entry>
    <entry>
        <title>Openai rachète Astral</title>
        <link href="https://linuxfr.org/users/quiwy/liens/openai-rachete-astral" />
        <id>https://linuxfr.org/users/quiwy/liens/openai-rachete-astral</id>
        <updated>2026-03-19T15:20:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://openai.com/index/openai-to-acquire-astral/">https://openai.com/index/openai-to-acquire-astral/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142696/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/quiwy/liens/openai-rachete-astral#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Quiwy</name>
        </author>
    </entry>
    <entry>
        <title>Vidéos PyConFR 2025</title>
        <link href="https://discuss.afpy.org/t/videos-pyconfr-2025/2962" />
        <id>https://discuss.afpy.org/t/videos-pyconfr-2025/2962</id>
        <updated>2026-03-19T07:07:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à toutes et tous,</p>
<p>Les vidéos de la PyConFR 2025 qui s’est tenue à Lyon en octobre/novembre derniers, déjà accessibles <a href="https://indymotion.fr/c/pyconfr2025/videos">depuis quelques semaines sur cette chaîne IndyMotion</a> sont maintenant référencées sur PyVideo : <a class="inline-onebox" href="https://pyvideo.org/events/pycon-fr-2025.html">PyVideo.org · PyCon FR 2025</a></p>
<p>Bon visionnage <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/videos-pyconfr-2025/2962">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Les bizarreries de NaN en Python avec les dictionnaires et les sets</title>
        <link href="https://brassnet.biz/blog/nan-is-weird.html" />
        <id>https://brassnet.biz/blog/nan-is-weird.html</id>
        <updated>2026-03-17T14:30:01Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Exploration des comportements surprenants de <code>float('nan')</code> en Python : chaque instance de NaN est hashable mais jamais égale à elle-même, ce qui produit des résultats contre-intuitifs dans les sets (10 NaN distincts) et les dictionnaires (clés inaccessibles). L’article démontre avec des exemples concrets pourquoi NaN crée des situations paradoxales dans les structures de données Python, bien que son utilisation comme clé de dictionnaire soit déconseillée en pratique.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/47579-les-bizarreries-de-nan-en-python-avec-les-dictionn#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/47579-les-bizarreries-de-nan-en-python-avec-les-dictionn">Les bizarreries de NaN en Python avec les dictionnaires et les sets</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Recherche évènement</title>
        <link href="https://discuss.afpy.org/t/recherche-evenement/2961" />
        <id>https://discuss.afpy.org/t/recherche-evenement/2961</id>
        <updated>2026-03-17T09:53:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Je suis à la recherche sur Paris d’un lieu et d’un animateur pour que l’on puisse réaliser notre kick off avec mon équipe.<br/>
L’idée serait de faire sur la matinée conférence ou workshop<br/>
Nous sommes 8 personnes et on aimerait un sujet lié autour de python / GCP / vuejs (ou autre)<br/>
Le niveau est très varié, cette équipe travaille dans la data<br/>
Cela peut être un sujet déjà présenté auparavant ou à co-construire</p>
<p>J’aimerais idéalement avant juin</p>
<p>N’hésitez pas à me contacter si intéressé ou si vous avez besoin de plus de détails</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/recherche-evenement/2961">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>drigaudie</name>
        </author>
    </entry>
    <entry>
        <title>Conversion de fichiers Excel vers PDF en Python</title>
        <link href="https://linuxfr.org/users/casie/journaux/conversion-de-fichiers-excel-vers-pdf-en-python" />
        <id>https://linuxfr.org/users/casie/journaux/conversion-de-fichiers-excel-vers-pdf-en-python</id>
        <updated>2026-03-17T02:52:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-pourquoi-convertir-excel-en-pdf">Pourquoi convertir Excel en PDF</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-configuration-de-lenvironnement">Configuration de l'environnement</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-processus-de-conversion-de-base">Processus de conversion de base</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-conformit%C3%A9-pdfa-pour-larchivage">Conformité PDF/A pour l'archivage</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-conversion-de-plages-de-cellules-sp%C3%A9cifiques">Conversion de plages de cellules spécifiques</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-ajustement-du-contenu-%C3%A0-la-largeur-de-page">Ajustement du contenu à la largeur de page</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-exemple-pratique--syst%C3%A8me-automatis%C3%A9-de-distribution-de-rapports">Exemple pratique : Système automatisé de distribution de rapports</a></li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-probl%C3%A8mes-courants-et-solutions">Problèmes courants et solutions</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-probl%C3%A8me-1--contenu-coup%C3%A9-dans-le-pdf">Problème 1 : Contenu coupé dans le PDF</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-probl%C3%A8me-2--mauvaise-qualit%C3%A9-dimpression">Problème 2 : Mauvaise qualité d'impression</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-probl%C3%A8me-3--erreurs-dans-les-formules">Problème 3 : Erreurs dans les formules</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-probl%C3%A8me-4--tailles-de-fichier-importantes">Problème 4 : Tailles de fichier importantes</a></li>
</ul>
</li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-r%C3%A9sum%C3%A9">Résumé</a></li>
</ul>
</li>
</ul>
<p><strong>NdM:</strong> le paquet Python présenté ci-dessous est un logiciel propriétaire avec licence annuelle payante, les prix annoncés commençant à 799 USD/an.</p>
<p>Dans les flux de travail de gestion documentaire et de rapports d'entreprise, la conversion de feuilles de calcul Excel au format PDF représente une opération fondamentale. Le format PDF préserve fidèlement la mise en page, empêche les modifications accidentelles et garantit un affichage cohérent sur différents appareils et plateformes. Cet article explore les méthodes efficaces pour convertir des fichiers Excel en PDF à l'aide de Python, tout en maintenant la qualité du formatage et en contrôlant divers paramètres de conversion.</p>
<h3 id="toc-pourquoi-convertir-excel-en-pdf">Pourquoi convertir Excel en PDF</h3>
<p>Les feuilles de calcul Excel excellent dans l'analyse et l'édition de données, mais elles présentent certaines limitations lors de la distribution :</p>
<ul>
<li>
<strong>Préservation de la mise en page</strong> : Les PDF maintiennent exactement le formatage des cellules, les largeurs de colonnes et la disposition des pages, quel que soit le système du lecteur</li>
<li>
<strong>Protection des données</strong> : Les PDF sont plus difficiles à modifier accidentellement, protégeant ainsi les calculs et données sensibles</li>
<li>
<strong>Visualisation universelle</strong> : Les destinataires peuvent consulter les PDF sans avoir besoin d'Excel ou d'un logiciel de tableur</li>
<li>
<strong>Prêt à imprimer</strong> : Les PDF sont optimisés pour l'impression avec des sauts de page et des marges cohérents</li>
<li>
<strong>Présentation professionnelle</strong> : Les PDF offrent une apparence soignée et finale pour les rapports et états financiers</li>
</ul>
<p>L'automatisation de cette conversion avec Python permet le traitement par lots de rapports financiers, la génération automatique de factures et l'intégration dans des pipelines de données plus vastes.</p>
<h3 id="toc-configuration-de-lenvironnement">Configuration de l'environnement</h3>
<p>Avant de commencer, vous devez installer une bibliothèque Python prenant en charge les opérations Excel. Spire.XLS for Python fournit des API complètes pour gérer les classeurs au format XLSX, y compris les fonctionnalités de conversion PDF.</p>
<pre><code class="bash">pip install Spire.XLS</code></pre>
<p>Une fois installée, importez les modules pertinents dans votre script Python :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">spire.xls</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">spire.xls.common</span> <span class="kn">import</span> <span class="o">*</span></code></pre>
<h3 id="toc-processus-de-conversion-de-base">Processus de conversion de base</h3>
<p>Les étapes principales pour convertir un fichier Excel en PDF sont simples : créer un objet classeur, charger le fichier Excel et enregistrer au format PDF. Voici un exemple minimal fonctionnel :</p>
<p>La méthode la plus directe pour convertir un fichier Excel consiste à utiliser l'objet <code>Workbook</code> qui gère automatiquement la structure du document. Cette approche fonctionne parfaitement pour des conversions rapides où vous souhaitez préserver l'intégralité du contenu et du formatage d'origine sans configuration supplémentaire :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">spire.xls</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">spire.xls.common</span> <span class="kn">import</span> <span class="o">*</span>

<span class="c1"># Définir les chemins d'entrée et de sortie</span>
<span class="n">inputFile</span> <span class="o">=</span> <span class="s2">"tableau.xlsx"</span>
<span class="n">outputFile</span> <span class="o">=</span> <span class="s2">"resultat.pdf"</span>

<span class="c1"># Créer un objet classeur</span>
<span class="n">workbook</span> <span class="o">=</span> <span class="n">Workbook</span><span class="p">()</span>

<span class="c1"># Charger le fichier Excel depuis le disque</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">LoadFromFile</span><span class="p">(</span><span class="n">inputFile</span><span class="p">)</span>

<span class="c1"># Configurer l'ajustement des feuilles pour un meilleur rendu PDF</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">ConverterSetting</span><span class="o">.</span><span class="n">SheetFitToPage</span> <span class="o">=</span> <span class="bp">True</span>

<span class="c1"># Enregistrer au format PDF</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">SaveToFile</span><span class="p">(</span><span class="n">outputFile</span><span class="p">,</span> <span class="n">FileFormat</span><span class="o">.</span><span class="n">PDF</span><span class="p">)</span>

<span class="c1"># Libérer les ressources</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Dispose</span><span class="p">()</span></code></pre>
<p>Ce code illustre le flux de conversion le plus élémentaire. L'objet <code>Workbook</code> gère le chargement et la gestion du fichier Excel, tandis que <code>SaveToFile()</code> avec <code>FileFormat.PDF</code> spécifie le PDF comme format de sortie. Le paramètre <code>SheetFitToPage</code> garantit que les feuilles de calcul sont correctement mises à l'échelle pour tenir dans les pages PDF.</p>
<h3 id="toc-conformité-pdfa-pour-larchivage">Conformité PDF/A pour l'archivage</h3>
<p>Pour l'archivage documentaire à long terme, le PDF/A constitue une version normalisée ISO du PDF conçue pour la préservation numérique. Convertir Excel en PDF/A assure que les documents resteront accessibles pendant des décennies :</p>
<p>Lorsque vos documents Excel contiennent des données financières, des registres légaux ou toute information nécessitant une conservation à long terme, il est essentiel d'utiliser le standard PDF/A. Cette norme garantit que tous les éléments visuels et texturaux sont intégrés dans le fichier, éliminant toute dépendance aux polices ou ressources externes :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">spire.xls</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">spire.xls.common</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">inputFile</span> <span class="o">=</span> <span class="s2">"donnees_financieres.xlsx"</span>
<span class="n">outputFile</span> <span class="o">=</span> <span class="s2">"copie_archivage.pdf"</span>

<span class="n">workbook</span> <span class="o">=</span> <span class="n">Workbook</span><span class="p">()</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">LoadFromFile</span><span class="p">(</span><span class="n">inputFile</span><span class="p">)</span>

<span class="c1"># Définir le niveau de conformité PDF sur PDF/A-1B</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">ConverterSetting</span><span class="o">.</span><span class="n">PdfConformanceLevel</span> <span class="o">=</span> <span class="n">PdfConformanceLevel</span><span class="o">.</span><span class="n">Pdf_A1B</span>

<span class="c1"># Enregistrer en PDF conforme PDF/A</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">SaveToFile</span><span class="p">(</span><span class="n">outputFile</span><span class="p">,</span> <span class="n">FileFormat</span><span class="o">.</span><span class="n">PDF</span><span class="p">)</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Dispose</span><span class="p">()</span></code></pre>
<p>Le paramètre <code>PdfConformanceLevel</code> offre plusieurs options :</p>
<ul>
<li>
<strong>Pdf_A1B</strong> : Conformité PDF/A-1 Niveau B - adaptée à la plupart des besoins d'archivage</li>
<li>
<strong>Pdf_A2B</strong> : Conformité PDF/A-2 Niveau B - prend en charge des fonctionnalités plus modernes</li>
<li>
<strong>Pdf_A3B</strong> : Conformité PDF/A-3 Niveau B - permet l'intégration de fichiers arbitraires</li>
</ul>
<p>La conformité PDF/A est essentielle pour les documents juridiques, les registres financiers et tout contenu nécessitant une préservation à long terme.</p>
<h3 id="toc-conversion-de-plages-de-cellules-spécifiques">Conversion de plages de cellules spécifiques</h3>
<p>Parfois, vous n'avez besoin d'exporter qu'une plage de données spécifique plutôt que des feuilles de calcul entières. Cette approche s'avère utile pour créer des résumés ou extraire des indicateurs clés :</p>
<p>Dans de nombreux scénarios professionnels, seul un sous-ensemble des données doit être partagé. Plutôt que de distribuer un classeur complet, vous pouvez isoler une section pertinente et la convertir indépendamment. Cette technique permet de générer des vues ciblées adaptées à différents publics ou objectifs :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">spire.xls</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">spire.xls.common</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">inputFile</span> <span class="o">=</span> <span class="s2">"rapport_trimestriel.xlsx"</span>
<span class="n">outputFile</span> <span class="o">=</span> <span class="s2">"section_resumé.pdf"</span>

<span class="n">workbook</span> <span class="o">=</span> <span class="n">Workbook</span><span class="p">()</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">LoadFromFile</span><span class="p">(</span><span class="n">inputFile</span><span class="p">)</span>

<span class="c1"># Ajouter une nouvelle feuille de calcul pour la plage sélectionnée</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="s2">"resume"</span><span class="p">)</span>

<span class="c1"># Copier la plage de cellules spécifique vers la nouvelle feuille</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">Range</span><span class="p">[</span><span class="s2">"A9:E15"</span><span class="p">]</span><span class="o">.</span><span class="n">Copy</span><span class="p">(</span>
    <span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">Range</span><span class="p">[</span><span class="s2">"A9:E15"</span><span class="p">],</span> 
    <span class="bp">False</span><span class="p">,</span>  <span class="c1"># Ne pas copier les formules</span>
    <span class="bp">True</span>    <span class="c1"># Copier le formatage</span>
<span class="p">)</span>

<span class="c1"># Ajuster automatiquement les largeurs de colonnes pour une meilleure apparence</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">Range</span><span class="p">[</span><span class="s2">"A9:E15"</span><span class="p">]</span><span class="o">.</span><span class="n">AutoFitColumns</span><span class="p">()</span>

<span class="c1"># Enregistrer uniquement la plage sélectionnée en PDF</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">SaveToPdf</span><span class="p">(</span><span class="n">outputFile</span><span class="p">)</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Dispose</span><span class="p">()</span></code></pre>
<p>Cette approche s'avère particulièrement utile lorsque :<br/>
- Vous créez des résumés exécutifs à partir de rapports détaillés<br/>
- Vous extrayez des tableaux de données spécifiques pour des présentations<br/>
- Vous générez des vues ciblées de grands ensembles de données<br/>
- Vous partagez des portions sélectionnées sans révéler les feuilles de calcul complètes</p>
<h3 id="toc-ajustement-du-contenu-à-la-largeur-de-page">Ajustement du contenu à la largeur de page</h3>
<p>Les feuilles de calcul Excel s'étendent souvent sur plusieurs colonnes qui peuvent ne pas bien s'adapter aux tailles de page standard. Vous pouvez configurer la mise en page pour forcer le contenu à tenir dans des dimensions spécifiées :</p>
<p>Lorsque vos tableaux Excel comportent de nombreuses colonnes, il est crucial de configurer correctement l'aperçu avant impression. Sans ajustement approprié, certaines colonnes pourraient être coupées ou apparaître sur des pages séparées, rendant la lecture difficile. La propriété <code>FitToPagesWide</code> résout ce problème en compressant horizontalement le contenu :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">spire.xls</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">spire.xls.common</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">inputFile</span> <span class="o">=</span> <span class="s2">"donnees_etendues.xlsx"</span>
<span class="n">outputFile</span> <span class="o">=</span> <span class="s2">"rapport_ajuste.pdf"</span>

<span class="n">workbook</span> <span class="o">=</span> <span class="n">Workbook</span><span class="p">()</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">LoadFromFile</span><span class="p">(</span><span class="n">inputFile</span><span class="p">)</span>

<span class="c1"># Configurer chaque feuille de calcul</span>
<span class="k">for</span> <span class="n">sheet</span> <span class="ow">in</span> <span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">:</span>
    <span class="c1"># Tenir sur une page de large (pas de limite d'échelle horizontale)</span>
    <span class="n">sheet</span><span class="o">.</span><span class="n">PageSetup</span><span class="o">.</span><span class="n">FitToPagesWide</span> <span class="o">=</span> <span class="mi">1</span>

    <span class="c1"># Pas de limite verticale (autoriser plusieurs pages en hauteur)</span>
    <span class="n">sheet</span><span class="o">.</span><span class="n">PageSetup</span><span class="o">.</span><span class="n">FitToPagesTall</span> <span class="o">=</span> <span class="mi">0</span>

<span class="c1"># Enregistrer avec la mise en page appliquée</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">SaveToFile</span><span class="p">(</span><span class="n">outputFile</span><span class="p">,</span> <span class="n">FileFormat</span><span class="o">.</span><span class="n">PDF</span><span class="p">)</span>
<span class="n">workbook</span><span class="o">.</span><span class="n">Dispose</span><span class="p">()</span></code></pre>
<p>Les paramètres de mise en page fonctionnent comme suit :</p>
<ul>
<li>
<strong>FitToPagesWide = 1</strong> : Force toutes les colonnes à tenir dans une seule largeur de page</li>
<li>
<strong>FitToPagesTall = 0</strong> : Autorise un nombre illimité de pages verticalement (pas d'échelle verticale)</li>
<li>
<strong>FitToPagesTall = 1</strong> : Forcerait la feuille entière sur une seule page</li>
</ul>
<p>Cette configuration garantit que les feuilles de calcul larges restent lisibles sans défilement horizontal excessif ni tailles de police minuscules.</p>
<h3 id="toc-exemple-pratique--système-automatisé-de-distribution-de-rapports">Exemple pratique : Système automatisé de distribution de rapports</h3>
<p>En combinant ces techniques, vous pouvez construire un système automatisé de distribution de rapports :</p>
<p>Pour illustrer l'application concrète de ces concepts, imaginons un scénario où vous devez générer régulièrement des rapports départementaux à partir d'un classeur maître. Un tel système nécessite non seulement la conversion en PDF, mais aussi l'organisation des fichiers, le suivi des versions et la personnalisation selon les destinataires :</p>
<pre><code class="python"><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">from</span> <span class="nn">spire.xls</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">spire.xls.common</span> <span class="kn">import</span> <span class="o">*</span>

<span class="k">class</span> <span class="nc">DistributeurRapportsExcel</span><span class="p">:</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">racine_rapports</span><span class="o">=</span><span class="s2">"rapports"</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">racine_rapports</span> <span class="o">=</span> <span class="n">racine_rapports</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">racine_rapports</span><span class="p">):</span>
            <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">racine_rapports</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">generer_rapport_mensuel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fichier_excel</span><span class="p">,</span> <span class="n">departement</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="sd">"""Générer un rapport PDF à partir d'un fichier Excel"""</span>

        <span class="c1"># Créer un sous-répertoire pour le département</span>
        <span class="k">if</span> <span class="n">departement</span><span class="p">:</span>
            <span class="n">dossier_dept</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">racine_rapports</span><span class="p">,</span> <span class="n">departement</span><span class="p">)</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">dossier_dept</span><span class="p">):</span>
                <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">dossier_dept</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">dossier_dept</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">racine_rapports</span>

        <span class="c1"># Générer un nom de fichier avec horodatage</span>
        <span class="n">horodatage</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">"%Y%m_%H%M%S"</span><span class="p">)</span>
        <span class="n">nom_base</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">fichier_excel</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">nom_pdf</span> <span class="o">=</span> <span class="s2">"{0}_{1}.pdf"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">nom_base</span><span class="p">,</span> <span class="n">horodatage</span><span class="p">)</span>
        <span class="n">chemin_pdf</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dossier_dept</span><span class="p">,</span> <span class="n">nom_pdf</span><span class="p">)</span>

        <span class="c1"># Effectuer la conversion</span>
        <span class="n">workbook</span> <span class="o">=</span> <span class="n">Workbook</span><span class="p">()</span>
        <span class="n">workbook</span><span class="o">.</span><span class="n">LoadFromFile</span><span class="p">(</span><span class="n">fichier_excel</span><span class="p">)</span>

        <span class="c1"># Optimiser pour la sortie PDF</span>
        <span class="n">workbook</span><span class="o">.</span><span class="n">ConverterSetting</span><span class="o">.</span><span class="n">SheetFitToPage</span> <span class="o">=</span> <span class="bp">True</span>

        <span class="c1"># Appliquer la mise en page à toutes les feuilles</span>
        <span class="k">for</span> <span class="n">sheet</span> <span class="ow">in</span> <span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">:</span>
            <span class="n">sheet</span><span class="o">.</span><span class="n">PageSetup</span><span class="o">.</span><span class="n">FitToPagesWide</span> <span class="o">=</span> <span class="mi">1</span>
            <span class="n">sheet</span><span class="o">.</span><span class="n">PageSetup</span><span class="o">.</span><span class="n">FitToPagesTall</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="n">workbook</span><span class="o">.</span><span class="n">SaveToFile</span><span class="p">(</span><span class="n">chemin_pdf</span><span class="p">,</span> <span class="n">FileFormat</span><span class="o">.</span><span class="n">PDF</span><span class="p">)</span>
        <span class="n">workbook</span><span class="o">.</span><span class="n">Dispose</span><span class="p">()</span>

        <span class="k">return</span> <span class="n">chemin_pdf</span>

    <span class="k">def</span> <span class="nf">distribuer_feuilles_classeur</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fichier_excel</span><span class="p">,</span> <span class="n">dossier_sortie</span><span class="p">):</span>
        <span class="sd">"""Extraire et enregistrer chaque feuille en PDF séparé"""</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">dossier_sortie</span><span class="p">):</span>
            <span class="n">os</span><span class="o">.</span><span class="n">makedirs</span><span class="p">(</span><span class="n">dossier_sortie</span><span class="p">)</span>

        <span class="n">workbook</span> <span class="o">=</span> <span class="n">Workbook</span><span class="p">()</span>
        <span class="n">workbook</span><span class="o">.</span><span class="n">LoadFromFile</span><span class="p">(</span><span class="n">fichier_excel</span><span class="p">)</span>

        <span class="n">fichiers_exportes</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">sheet</span> <span class="ow">in</span> <span class="n">workbook</span><span class="o">.</span><span class="n">Worksheets</span><span class="p">:</span>
            <span class="n">nom_pdf</span> <span class="o">=</span> <span class="n">sheet</span><span class="o">.</span><span class="n">Name</span> <span class="o">+</span> <span class="s2">".pdf"</span>
            <span class="n">chemin_pdf</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dossier_sortie</span><span class="p">,</span> <span class="n">nom_pdf</span><span class="p">)</span>

            <span class="n">sheet</span><span class="o">.</span><span class="n">SaveToPdf</span><span class="p">(</span><span class="n">chemin_pdf</span><span class="p">)</span>
            <span class="n">fichiers_exportes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">chemin_pdf</span><span class="p">)</span>
            <span class="k">print</span><span class="p">(</span><span class="s2">"Feuille exportée : {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">chemin_pdf</span><span class="p">))</span>

        <span class="n">workbook</span><span class="o">.</span><span class="n">Dispose</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">fichiers_exportes</span>

<span class="c1"># Exemple d'utilisation</span>
<span class="n">distributeur</span> <span class="o">=</span> <span class="n">DistributeurRapportsExcel</span><span class="p">(</span><span class="s2">"rapports_mensuels"</span><span class="p">)</span>
<span class="n">rapport_pdf</span> <span class="o">=</span> <span class="n">distributeur</span><span class="o">.</span><span class="n">generer_rapport_mensuel</span><span class="p">(</span>
    <span class="s2">"donnees_ventes.xlsx"</span><span class="p">,</span> 
    <span class="n">departement</span><span class="o">=</span><span class="s2">"ventes"</span>
<span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s2">"Rapport généré : {0}"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rapport_pdf</span><span class="p">))</span></code></pre>
<p>Ce système de distribution offre :<br/>
- Une organisation par département<br/>
- Un suivi par horodatage pour le contrôle de version<br/>
- Une exportation flexible en fichier unique ou feuilles multiples<br/>
- Une optimisation automatique des pages</p>
<h3 id="toc-problèmes-courants-et-solutions">Problèmes courants et solutions</h3>
<h4 id="toc-problème-1--contenu-coupé-dans-le-pdf">Problème 1 : Contenu coupé dans le PDF</h4>
<p>Ajustez la mise en page pour adapter correctement le contenu :</p>
<pre><code class="python"><span class="n">sheet</span><span class="o">.</span><span class="n">PageSetup</span><span class="o">.</span><span class="n">FitToPagesWide</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">sheet</span><span class="o">.</span><span class="n">PageSetup</span><span class="o">.</span><span class="n">FitToPagesTall</span> <span class="o">=</span> <span class="mi">0</span></code></pre>
<h4 id="toc-problème-2--mauvaise-qualité-dimpression">Problème 2 : Mauvaise qualité d'impression</h4>
<p>Assurez-vous d'activer les paramètres de haute qualité :</p>
<pre><code class="python"><span class="n">workbook</span><span class="o">.</span><span class="n">ConverterSetting</span><span class="o">.</span><span class="n">SheetFitToPage</span> <span class="o">=</span> <span class="bp">True</span></code></pre>
<h4 id="toc-problème-3--erreurs-dans-les-formules">Problème 3 : Erreurs dans les formules</h4>
<p>Si vous copiez des plages, décidez s'il faut copier les formules ou les valeurs :</p>
<pre><code class="python"><span class="c1"># Copier uniquement les valeurs (sans les formules)</span>
<span class="nb">range</span><span class="o">.</span><span class="n">Copy</span><span class="p">(</span><span class="n">target_range</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="bp">True</span><span class="p">)</span></code></pre>
<h4 id="toc-problème-4--tailles-de-fichier-importantes">Problème 4 : Tailles de fichier importantes</h4>
<p>Pour des besoins d'archivage où la taille compte, envisagez un PDF standard plutôt que PDF/A :</p>
<pre><code class="python"><span class="n">workbook</span><span class="o">.</span><span class="n">ConverterSetting</span><span class="o">.</span><span class="n">PdfConformanceLevel</span> <span class="o">=</span> <span class="n">PdfConformanceLevel</span><span class="o">.</span><span class="n">None</span></code></pre>
<h3 id="toc-résumé">Résumé</h3>
<p>La conversion de fichiers Excel en PDF constitue une compétence essentielle pour la génération automatique de rapports et la gestion documentaire. Tout au long de cet article, nous avons appris :</p>
<ol>
<li>Comment charger et convertir des fichiers Excel à l'aide de l'objet <code>Workbook</code>
</li>
<li>Créer des documents conformes PDF/A pour l'archivage à long terme</li>
<li>Exporter des plages de cellules spécifiques pour des rapports ciblés</li>
<li>Configurer la mise en page pour adapter le contenu de manière appropriée</li>
<li>Construire des systèmes de conversion par lots pour une utilisation en production</li>
</ol>
<p>Ces techniques s'appliquent directement à la reporting financier, à la génération automatique de factures, aux tableaux de bord d'intelligence économique et aux flux de travail de conformité réglementaire. Après avoir maîtrisé la conversion de base, vous pouvez explorer des fonctionnalités avancées telles que la protection par mot de passe, les signatures numériques et les filigranes personnalisés pour construire des solutions d'automatisation documentaire complètes.</p>
<div><a href="https://linuxfr.org/users/casie/journaux/conversion-de-fichiers-excel-vers-pdf-en-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142666/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/casie/journaux/conversion-de-fichiers-excel-vers-pdf-en-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Casie</name>
        </author>
    </entry>
    <entry>
        <title>Linux Hardening : une approche pragmatique</title>
        <link href="https://bearstech.com/societe/blog/linux-hardening-une-approche-pragmatique-transcript-de-webinaire" />
        <id>https://bearstech.com/societe/blog/linux-hardening-une-approche-pragmatique-transcript-de-webinaire</id>
        <updated>2026-03-13T14:18:22Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>L’économie du logiciel est-elle morte ?</title>
        <link href="https://linuxfr.org/news/l-economie-du-logiciel-est-elle-morte" />
        <id>https://linuxfr.org/news/l-economie-du-logiciel-est-elle-morte</id>
        <updated>2026-03-13T12:35:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Dan Blanchard vient de publier une nouvelle version de <a href="https://github.com/chardet/chardet">Chardet</a>, une bibliothèque Python largement utilisée, sous licence MIT permissive, alors que les versions précédentes étaient sous licence GNU LGPL. Comment est-ce possible, étant donné que Dan est le responsable de cette bibliothèque, mais qu’il n’en est ni l’auteur originel ni le seul contributeur ? La réponse est très simple et d’actualité : cette version est une réécriture complète du projet, réalisée par l’IA Claude en cinq jours. Elle n’emprunte aucun fragment de code aux versions antérieures. Plus précisément, les quelques correspondances identifiées (1,3 % du code) ne sont pas spécifiques à Chardet. Elles correspondent à des idiomatismes dans les projets en Python.</p>
<p>Après avoir mené ses propres expériences, tout aussi convaincantes, <a href="https://fr.wikipedia.org/wiki/Bruce_Perens">Bruce Perens</a> a récemment déclaré :</p>
<blockquote>
<p>Je brise la vitre et déclenche l’alarme incendie ! Toute l’économie du développement logiciel est morte, disparue, finie, kaput !</p>
</blockquote>
<p>Comme le souligne Bruce Perens, ce problème n’est pas spécifique aux logiciels libres. Les éditeurs de logiciels indépendants et leur modèle économique sont également <a href="https://fr.wikipedia.org/wiki/Ub%C3%A9risation">ubérisés</a> par les IA génératives. Et, bien sûr, cette question existentielle concerne également les ESN (i.e. les sociétés de service).</p>
<p><strong>NdM:</strong> des infos complémentaires en provenance du <a href="https://linuxfr.org/users/thoasm/liens/apparently-chardet-got-claude-to-rewrite-the-entire-codebase-from-lgpl-to-mit">lien</a> ayant déjà généré quelques commentaires : d’abord l’auteur originel de Chardet <a href="https://github.com/chardet/chardet/issues/327">demande d’annuler</a> ce changement de licence qu’il considère comme une violation des droits ; et déjà au moins un ticket <a href="https://github.com/chardet/chardet/issues/331">considérant un risque juridique « v7.0.0 presents unacceptable legal risk to users due to copyright controversy »</a>. Sont aussi mentionnés un article <a href="https://lwn.net/Articles/1061534/">LWN</a> (accès réservé aux abonnés jusqu’au 19 mars et accès libre ensuite), et un autre cas de réécriture d’une application dans un autre langage et une autre licence, mais faite d’une toute autre manière avec <a href="https://linuxfr.org/users/uso/journaux/amelioration-dans-gnu-coreutils-par-les-dev-de-uutils-en-rust">GNU Coreutils (C, GPL) et uutils (Rust, MIT)</a>. Encore d’autres articles via <a href="https://www.phoronix.com/news/Chardet-LLM-Rewrite-Relicense">Phoronix</a> ou <a href="https://developers.slashdot.org/story/26/03/06/1614252/python-chardet-package-replaced-with-llm-generated-clone-re-licensed">Slashdot</a> ou <a href="https://fr.linkedin.com/posts/julien-mutzenhardt_chardet-quand-une-ia-r%C3%A9%C3%A9crit-un-logiciel-activity-7435742245728899072-F7eq">LinkedIn</a> ou…</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/117179" hreflang="en" title="https://www.theregister.com/2026/03/06/ai_kills_software_licensing/">Article détaillé sur The Register</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/117180" hreflang="fr" title="https://korben.info/chardet-quand-une-ia-reecrit-un-logiciel-open-source-en-cinq-jours-et-change-sa-licence.html">Article plus sommaire sur Korben.info</a></li></ul><div></div><div><a href="https://linuxfr.org/news/l-economie-du-logiciel-est-elle-morte.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142604/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/l-economie-du-logiciel-est-elle-morte#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Sébastien Dinot,Benoît Sibaud,Ysabeau  🧶,Julien Jorge,patrick_g</name>
        </author>
    </entry>
    <entry>
        <title>Python 3.15 introduit le mot-clé lazy pour les imports paresseux</title>
        <link href="https://techlife.blog/posts/the-story-of-pythons-lazy-imports-why-it-took-three-years-and-two-attempts/" />
        <id>https://techlife.blog/posts/the-story-of-pythons-lazy-imports-why-it-took-three-years-and-two-attempts/</id>
        <updated>2026-03-11T12:20:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Après trois ans de débats et deux PEPs, Python 3.15 intègre officiellement les imports paresseux via le mot-clé <code>lazy</code>. Meta et Hudson River Trading avaient déjà implémenté cette fonctionnalité dans leurs forks de CPython, avec des gains impressionnants : jusqu’à 70% de réduction du temps de démarrage et 40% de mémoire économisée. Le PEP 690 avait été rejeté pour son approche globale, tandis que le PEP 810 a été accepté à l’unanimité grâce à son design explicite et les preuves d’efficacité en production.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/46688-python-3-15-introduit-le-mot-cle-lazy-pour-les-imp#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/46688-python-3-15-introduit-le-mot-cle-lazy-pour-les-imp">Python 3.15 introduit le mot-clé lazy pour les imports paresseux</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Sur Rennes - meetup le mardi 17 mars 2026 : Optimiser son intégration continue de projet Python (mais pas que)</title>
        <link href="https://discuss.afpy.org/t/sur-rennes-meetup-le-mardi-17-mars-2026-optimiser-son-integration-continue-de-projet-python-mais-pas-que/2956" />
        <id>https://discuss.afpy.org/t/sur-rennes-meetup-le-mardi-17-mars-2026-optimiser-son-integration-continue-de-projet-python-mais-pas-que/2956</id>
        <updated>2026-03-10T14:17:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a class="anchor" href="https://discuss.afpy.org#p-12773-optimiser-son-intgration-continue-de-projet-python-mais-pas-que-1" name="p-12773-optimiser-son-intgration-continue-de-projet-python-mais-pas-que-1"></a>Optimiser son intégration continue de projet Python (mais pas que)</h1>
<p>Évènement détaillé sur <a class="inline-onebox" href="https://www.meetup.com/fr-fr/python-rennes/events/313623596/" rel="noopener nofollow ugc">Optimiser son intégration continue de projet Python (mais pas que), mar. 17 mars 2026, 18:45 | Meetup</a>.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-rennes-meetup-le-mardi-17-mars-2026-optimiser-son-integration-continue-de-projet-python-mais-pas-que/2956">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>luc_sorel-giffo</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 19 mars</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-mars/2955" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-19-mars/2955</id>
        <updated>2026-03-09T10:35:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Le prochain meetup à Lyon est le 19 mars, à 19h, où <a class="mention" href="https://discuss.afpy.org/u/fcodvpt">@fcodvpt</a> nous parlera de MkDocs !</p>
<p>Nous serons accueillis par OVHcloud (métro Garibaldi).</p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-mars/2955/1" style="font-weight: bold; font-size: 1.1em;">Créer un site web facilement avec MkDocs… c'est fini ?</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">March 19, 2026 7:00 PM (Europe/Paris) → March 19, 2026 10:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://www.meetup.com/fr-fr/python-afpy-lyon/events/313505021/</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-mars/2955">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Learn Claude Code -- A nano Claude Code-like agent, built from 0 to 1</title>
        <link href="https://linuxfr.org/users/gbetous/liens/learn-claude-code-a-nano-claude-code-like-agent-built-from-0-to-1" />
        <id>https://linuxfr.org/users/gbetous/liens/learn-claude-code-a-nano-claude-code-like-agent-built-from-0-to-1</id>
        <updated>2026-03-07T08:30:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://github.com/shareAI-lab/learn-claude-code">https://github.com/shareAI-lab/learn-claude-code</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142554/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/gbetous/liens/learn-claude-code-a-nano-claude-code-like-agent-built-from-0-to-1#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>gUI</name>
        </author>
    </entry>
    <entry>
        <title>Lecture de plusieurs pistes avec QMediaPlayer - PySide 6</title>
        <link href="https://discuss.afpy.org/t/lecture-de-plusieurs-pistes-avec-qmediaplayer-pyside-6/2948" />
        <id>https://discuss.afpy.org/t/lecture-de-plusieurs-pistes-avec-qmediaplayer-pyside-6/2948</id>
        <updated>2026-03-02T07:16:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>J’essaie de créer un programme qui doit lire des pistes mp3, j’ai opté pour QMediaPlayer, le widget de Qt pour atteindre mon objectif, mais il se trouve que si je lui fournis deux fichiers à lire, il ne lit que le dernier, je pense que c’est parce que le programme suit son cheminement et que la seconde directive écrase la première et que c’est pour ça qu’il ne lit que le dernier fichier fourni, je joins ici mon code dans l’espoir de trouver de l’aide.</p>
<pre><code class="lang-python">self.player=QMediaPlayer()
self.audioOutput = QAudioOutput()

self.player.setAudioOutput(self.audioOutput)

self.player.setSource(QUrl.fromLocalFile(“sound/001000.mp3”))

self.player.play()

while self.player.isPlaying():

time.sleep(2)

self.player.setSource(QUrl.fromLocalFile(“sound/001001.mp3”))

self.player.play()
</code></pre>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/lecture-de-plusieurs-pistes-avec-qmediaplayer-pyside-6/2948">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mahmoud</name>
        </author>
    </entry>
    <entry>
        <title>Conférences éclair APRIL 2026</title>
        <link href="https://discuss.afpy.org/t/conferences-eclair-april-2026/2946" />
        <id>https://discuss.afpy.org/t/conferences-eclair-april-2026/2946</id>
        <updated>2026-02-26T08:57:40Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>bonjour à toutes et à tous,</p>
<p>L’assemblée générale de l’April aura lieu samedi 28 mars 2026 à Paris (Jussieu), l’AG est réservée aux membres de l’April mais <strong>un temps de conférences éclairs ouvert à toute personne, membre ou pas de l’April</strong>, est prévu le matin de 10 h à 12 h.</p>
<p>Outre l’intervention (et donc faire découvrir un sujet), cela peut apporter à la personne :</p>
<ul>
<li>rencontrer d’autres libristes</li>
<li>découvrir plein de sujets sans crainte de s’ennuyer</li>
<li>partager un repas tiré du sac sur le temps de midi dans un esprit convivial</li>
</ul>
<p>Pour réussir une session de conférences éclairs, il faut des intervenants et des intervenantes. Nous en attendons une quinzaine.</p>
<p>Le format court, 6 minutes, et le contexte amical offrent un cadre rassurant.</p>
<p>Si vous êtes sur Paris ou alentours, n’hésitez pas à postuler</p>
<ul>
<li>Date limite pour postuler : 15 mars 2026</li>
<li>L’appel à proposition : <a class="inline-onebox" href="https://www.april.org/appel-a-conferences-eclairs-pour-le-matin-de-l-ag-de-l-april-samedi-28-mars-2026-a-paris" rel="noopener nofollow ugc">Appel à conférences éclairs pour le matin de l'AG de l'April - samedi 28 mars 2026 à Paris | April</a></li>
</ul>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/conferences-eclair-april-2026/2946">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>fcodvpt</name>
        </author>
    </entry>
    <entry>
        <title>Rivalcfg: New standalone builds for Linux, macOS and Windows</title>
        <link href="https://linuxfr.org/users/flozz/liens/rivalcfg-new-standalone-builds-for-linux-macos-and-windows" />
        <id>https://linuxfr.org/users/flozz/liens/rivalcfg-new-standalone-builds-for-linux-macos-and-windows</id>
        <updated>2026-02-24T18:19:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://rivalcfg.flozz.org/news/new-standalone-builds-for-linux-macos-and-windows/">https://rivalcfg.flozz.org/news/new-standalone-builds-for-linux-macos-and-windows/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142407/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/flozz/liens/rivalcfg-new-standalone-builds-for-linux-macos-and-windows#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>FLOZz</name>
        </author>
    </entry>
    <entry>
        <title>IA et Cybersécurité : une catastrophe à venir</title>
        <link href="https://bearstech.com/societe/blog/ia-et-cybersecurite-une-catastrophe-venir" />
        <id>https://bearstech.com/societe/blog/ia-et-cybersecurite-une-catastrophe-venir</id>
        <updated>2026-02-24T09:34:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>Multi-Language MCP Server Performance Benchmark</title>
        <link href="https://linuxfr.org/users/yboy360/liens/multi-language-mcp-server-performance-benchmark" />
        <id>https://linuxfr.org/users/yboy360/liens/multi-language-mcp-server-performance-benchmark</id>
        <updated>2026-02-22T11:01:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.tmdevlab.com/mcp-server-performance-benchmark.html">https://www.tmdevlab.com/mcp-server-performance-benchmark.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142381/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/yboy360/liens/multi-language-mcp-server-performance-benchmark#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>YBoy360</name>
        </author>
    </entry>
    <entry>
        <title>Selenium &gt;&gt; Anubis et cie</title>
        <link href="https://linuxfr.org/users/killruana/journaux/selenium-anubis-et-cie" />
        <id>https://linuxfr.org/users/killruana/journaux/selenium-anubis-et-cie</id>
        <updated>2026-02-19T18:03:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Vous faites chier avec vos trucs genre <a href="https://github.com/TecharoHQ/anubis">Anubis</a> qui cassent mes petits scrapers python :(</p>
<p>Là, je voulais gentiment scraper les missions sur le <a href="https://cyberpunk.fandom.com/wiki/Cyberpunk_2077_Main_Jobs">Fandom de Cyberpunk 2077</a> pour pouvoir faire mon arbre de mission.</p>
<p>Et pouf, on se fait rembarrer parce qu'on utilise pas un vrai navigateur :</p>
<pre><code class="shell">$ curl -v https://cyberpunk.fandom.com/wiki/Cyberpunk_2077_Main_Jobs
&gt; Host: cyberpunk.fandom.com
&gt; User-Agent: curl/8.18.0
&gt; Accept: */*
&gt; 
&lt; HTTP/2 <span class="m">403</span></code></pre>
<p>Dans ces cas là, pas le choix, <a href="https://www.selenium.dev/documentation/webdriver/">Selenium WebDriver</a>.</p>
<p>WebDriver est lib multilangage pour contrôler un navigateur web tel que firefox ou chrome.</p>
<p>Minimal Viable Product®</p>
<pre><code class="python3"><span class="ch">#!/usr/bin/env python3</span>
<span class="kn">from</span> <span class="nn">pathlib</span> <span class="k">import</span> <span class="n">Path</span>

<span class="kn">from</span> <span class="nn">selenium</span> <span class="k">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">selenium.webdriver.common.by</span> <span class="k">import</span> <span class="n">By</span>


<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">output_dir</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s2">"html"</span><span class="p">)</span>
    <span class="n">output_dir</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="n">exist_ok</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

    <span class="n">driver</span> <span class="o">=</span> <span class="n">webdriver</span><span class="o">.</span><span class="n">Firefox</span><span class="p">()</span>
    <span class="n">driver</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"https://cyberpunk.fandom.com/wiki/Cyberpunk_2077_Main_Jobs"</span><span class="p">)</span>

    <span class="n">links</span> <span class="o">=</span> <span class="p">[</span>
        <span class="p">(</span><span class="n">link</span><span class="o">.</span><span class="n">get_attribute</span><span class="p">(</span><span class="s2">"title"</span><span class="p">),</span> <span class="n">link</span><span class="o">.</span><span class="n">get_attribute</span><span class="p">(</span><span class="s2">"href"</span><span class="p">))</span>
        <span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">driver</span><span class="o">.</span><span class="n">find_elements</span><span class="p">(</span><span class="n">By</span><span class="o">.</span><span class="n">CSS_SELECTOR</span><span class="p">,</span> <span class="s2">".navbox li a"</span><span class="p">)</span>
    <span class="p">]</span>
    <span class="k">for</span> <span class="n">link_title</span><span class="p">,</span> <span class="n">link_href</span> <span class="ow">in</span> <span class="n">links</span><span class="p">:</span>
        <span class="n">page_file</span> <span class="o">=</span> <span class="n">output_dir</span> <span class="o">/</span> <span class="n">f</span><span class="s2">"</span><span class="si">{link_title}</span><span class="s2">.html"</span>
        <span class="k">if</span> <span class="n">page_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="s2">"</span><span class="si">{link_title}</span><span class="s2"> already exists, skipping"</span><span class="p">)</span>
            <span class="k">continue</span>
        <span class="nb">print</span><span class="p">(</span><span class="n">f</span><span class="s2">"Saving </span><span class="si">{link_title}</span><span class="s2"> from </span><span class="si">{link_href}</span><span class="s2">"</span><span class="p">)</span>

        <span class="n">driver</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">link_href</span><span class="p">)</span>
        <span class="n">content_node</span> <span class="o">=</span> <span class="n">driver</span><span class="o">.</span><span class="n">find_element</span><span class="p">(</span><span class="n">By</span><span class="o">.</span><span class="n">CSS_SELECTOR</span><span class="p">,</span> <span class="s2">".mw-parser-output"</span><span class="p">)</span>
        <span class="n">page_file</span><span class="o">.</span><span class="n">write_text</span><span class="p">(</span><span class="n">content_node</span><span class="o">.</span><span class="n">get_attribute</span><span class="p">(</span><span class="s2">"outerHTML"</span><span class="p">))</span>

    <span class="n">driver</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>


<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span></code></pre>
<p>j'trouve ça moins élégant que <a href="https://hishel.com/1.0/">Hishel</a>. Mais bon.</p>
<p><img alt="Modern Problems Require Modern Solutions " src="https://img.linuxfr.org/img/68747470733a2f2f692e696d67666c69702e636f6d2f616b6b626b642e6a7067/akkbkd.jpg" title="Source : https://i.imgflip.com/akkbkd.jpg"/></p>
<div><a href="https://linuxfr.org/users/killruana/journaux/selenium-anubis-et-cie.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142358/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/killruana/journaux/selenium-anubis-et-cie#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>jtremesay</name>
        </author>
    </entry>
    <entry>
        <title>Sur Grenoble - Meetup le 24 février 2026</title>
        <link href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-24-fevrier-2026/2942" />
        <id>https://discuss.afpy.org/t/sur-grenoble-meetup-le-24-fevrier-2026/2942</id>
        <updated>2026-02-18T22:01:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>On organise à Grenoble mardi 24 février 2026 un Meetup Python pour faire un partage d’expérience sur l’utilisation de l’intelligence artificielle générative pour le code Python.</p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-24-fevrier-2026/2942/1" style="font-weight: bold; font-size: 1.1em;">Partage d'expérience sur l'IA générative pour le code Python</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">February 24, 2026 7:00 PM (Europe/Paris) → February 24, 2026 9:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">La Turbine.coop</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-24-fevrier-2026/2942">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Pierre-Loic</name>
        </author>
    </entry>
    <entry>
        <title>Que faut-il savoir pour créer un meetup python chez soi ?</title>
        <link href="https://discuss.afpy.org/t/que-faut-il-savoir-pour-creer-un-meetup-python-chez-soi/2941" />
        <id>https://discuss.afpy.org/t/que-faut-il-savoir-pour-creer-un-meetup-python-chez-soi/2941</id>
        <updated>2026-02-18T06:05:10Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, j’aimerais créer un document qui prends les divers retour d’expériences des créateur•trices de Meetup python locaux afin d’aider à lancer le pas de nouveaux meetup.</p>
<ul>
<li>L’aide fournit par l’AFPy ?
<ul>
<li>Communication ?</li>
<li>Matériel ?</li>
<li>Compte meetup ? Mobilizon ?</li>
</ul>
</li>
<li>Guide pour créer un meetup étape par étape:
<ul>
<li>Comment trouver un lieu d’accueil ?</li>
<li>Comment trouver des personnes prêtes à faire des conférences ?</li>
<li>Comment organiser la communication de l’évènement ?</li>
<li>Comment partager les médias de l’évènement ?</li>
<li>Respecter la charte AFPy</li>
<li>(d’autres questions auxquels je ne pense pas)</li>
</ul>
</li>
</ul>
<p>Ce qu’on peut mettre en place en tant qu’AFPy ?</p>
<ul>
<li>Aide aux visuels (fournir des templates)</li>
</ul>
<p>Si les créatrices ou créateurs de meetup locaux veulent compléter ma liste absolument non-exhaustive, ça serait avec plaisir.</p>
<p><small>5 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/que-faut-il-savoir-pour-creer-un-meetup-python-chez-soi/2941">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Melcore</name>
        </author>
    </entry>
    <entry>
        <title>Je me suis remis sur Rivalcfg après une longue pause !</title>
        <link href="https://linuxfr.org/users/flozz/liens/je-me-suis-remis-sur-rivalcfg-apres-une-longue-pause" />
        <id>https://linuxfr.org/users/flozz/liens/je-me-suis-remis-sur-rivalcfg-apres-une-longue-pause</id>
        <updated>2026-02-16T05:53:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://blog.flozz.fr/2026/02/16/je-me-suis-remis-sur-rivalcfg-apres-une-longue-pause/">https://blog.flozz.fr/2026/02/16/je-me-suis-remis-sur-rivalcfg-apres-une-longue-pause/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142310/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/flozz/liens/je-me-suis-remis-sur-rivalcfg-apres-une-longue-pause#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>FLOZz</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 19 février</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-fevrier/2935" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-19-fevrier/2935</id>
        <updated>2026-02-09T12:31:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Le prochain meetup a lieu le jeudi 19 février à 19h, dans les locaux de Zenika (métro Brotteaux).</p>
<p><a class="mention" href="https://discuss.afpy.org/u/titimoby">@TitiMoby</a> présentera plein de chemins d’apprentissage du code, des outils, des plateformes… <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=15" title=":snake:" width="20"/></p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-fevrier/2935/1" style="font-weight: bold; font-size: 1.1em;">Apprendre à coder ou comment s’amuser de 7 à 77 ans</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">February 19, 2026 7:00 PM (Europe/Paris) → February 19, 2026 9:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://www.meetup.com/fr-fr/python-afpy-lyon/events/313021862/</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-fevrier/2935">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Offpunk 3.0</title>
        <link href="https://linuxfr.org/users/ploum/journaux/sortie-de-offpunk-3-0" />
        <id>https://linuxfr.org/users/ploum/journaux/sortie-de-offpunk-3-0</id>
        <updated>2026-02-09T10:45:40Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut Nal,</p>
<p>Après des semaines intensives de travail, j’ai le plaisir de t’annoncer la sortie d’Offpunk 3.0.</p>
<p><a href="https://ploum.net/2026-02-09-offpunk3.html">https://ploum.net/2026-02-09-offpunk3.html</a></p>
<p>Offpunk est un navigateur web/gemini/gopher/spartan en ligne de commande et déconnecté (oui, tout est en cache qu’on peut synchroniser régulièrement)</p>
<p>Pour avoir des réponses à toutes tes questions:</p>
<p><a href="https://offpunk.net/">https://offpunk.net/</a><br/>
gemini://offpunk.net/</p>
<p>ou bien l’installer et taper "tutorial"</p>
<p>Dans les grosses nouveautés de la 3.0, il faut noter:</p>
<ol>
<li>Support des traductions. Offpunk est traduit en Espagnol, en Galego et en Néerlandais mais pas encore en français ! Si vous voulez aider, c’est ici:</li>
</ol>
<p><a href="https://offpunk.net/translation.html">https://offpunk.net/translation.html</a></p>
<ol>
<li>Support de "unmerdify", par @vjousse. Unmerdify est une libraire qui va parser les pages HTML en utilisant les règles FiveFilters afin d’en extraire le contenu intéressant et jeter tout  les reste.</li>
</ol>
<p>Unmerdify: <a href="https://codeberg.org/vjousse/unmerdify">https://codeberg.org/vjousse/unmerdify</a></p>
<p>Contribuer aux filtres: <a href="https://help.fivefilters.org/full-text-rss/site-patterns.html#github-repository">https://help.fivefilters.org/full-text-rss/site-patterns.html#github-repository</a></p>
<ol>
<li>xkcdpunk, un utilitaire en ligne de commande pour afficher directement un comic XKCD dans son terminal.</li>
</ol>
<p>Et plein d’autres choses</p>
<p>Je te laisse découvrir toutes les autres nouveautés, n’hésite pas à me poser des questions !</p>
<div><a href="https://linuxfr.org/users/ploum/journaux/sortie-de-offpunk-3-0.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142226/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/ploum/journaux/sortie-de-offpunk-3-0#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>ploum</name>
        </author>
    </entry>
    <entry>
        <title>Sur Bordeaux le 26 février</title>
        <link href="https://discuss.afpy.org/t/sur-bordeaux-le-26-fevrier/2934" />
        <id>https://discuss.afpy.org/t/sur-bordeaux-le-26-fevrier/2934</id>
        <updated>2026-02-09T08:40:57Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p></p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/c/c515d1c739cae4159ae74c5e195d9afc4a59098c.jpeg" title="meetup-python-brouillon"><img alt="meetup-python-brouillon" height="394" src="https://discuss.afpy.org/uploads/default/optimized/2X/c/c515d1c739cae4159ae74c5e195d9afc4a59098c_2_690x394.jpeg" width="690"/></a></div><p></p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-bordeaux-le-26-fevrier/2934/1" style="font-weight: bold; font-size: 1.1em;">Meetup Python Bordeaux</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">February 26, 2026 6:30 PM (Europe/Paris) → February 26, 2026 9:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://cartes.app/?allez=Yack+-+coworking+B%25C3%25A9glais%7Cn11921858725%7C-0.55185%7C44.81310</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-bordeaux-le-26-fevrier/2934">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>yoan</name>
        </author>
    </entry>
    <entry>
        <title>pypi.org vient de dépasser les 100 milliards de paquets délivrés par mois</title>
        <link href="https://discuss.afpy.org/t/pypi-org-vient-de-depasser-les-100-milliards-de-paquets-delivres-par-mois/2933" />
        <id>https://discuss.afpy.org/t/pypi-org-vient-de-depasser-les-100-milliards-de-paquets-delivres-par-mois/2933</id>
        <updated>2026-02-06T11:08:39Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Depuis janvier 2026 :</p>
<p><img alt="https://git.afpy.org/mdk/python-versions/" height="459" src="https://git.afpy.org/mdk/python-versions/media/branch/main/pypi-download-counts.png" width="690"/></p>
<p>Source (et autres graphs) : <a class="inline-onebox" href="https://git.afpy.org/mdk/python-versions/">mdk/python-versions: Studying Python release adoptions by looking at PyPI downloads - La forge de l'AFPy</a></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/pypi-org-vient-de-depasser-les-100-milliards-de-paquets-delivres-par-mois/2933">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Développeur.se python fullstack (Nantes)</title>
        <link href="https://discuss.afpy.org/t/developpeur-se-python-fullstack-nantes/2932" />
        <id>https://discuss.afpy.org/t/developpeur-se-python-fullstack-nantes/2932</id>
        <updated>2026-02-05T16:43:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Nous recherchons un·e développeur·se avec déjà une première expérience professionnelle significative en Python pour poursuivre le développement de nos services. Avoir également de l’expérience avec Vue, Typescript, Docker ou Ansible est un plus.</p>
<p>Type d’emploi : CDI ou CDD, temps plein ou 4/5, poste sur Nantes (présentiel mini 2/3 jours par semaine)<br/>
<em>Ce n’est pas un poste de data scientist.</em></p>
<p><strong>Qui est OctopusMind ?</strong></p>
<p>OctopusMind, spécialiste de l’Open Data économique, développe des services autour de l’analyse des données. Nous éditons principalement une plateforme mondiale de détection d’appels d’offres : <a href="https://www.j360.info/" rel="noopener nofollow ugc">www.j360.info </a><br/>
L’entreprise, d’une dizaine de personnes, développe ses propres outils pour analyser quotidiennement une grande masse de données, en alliant intelligence humaine et artificielle <a href="https://www.octopusmind.info/" rel="noopener nofollow ugc">www.octopusmind.info </a><br/>
Nous recherchons pour ce poste un collaborateur habitant à proximité de Nantes.</p>
<p><strong>Nous vous proposons</strong></p>
<p>L’équipe IT, sans lead developer, est en lien avec l’équipe R&amp;D ML et l’équipe de veille des marchés. Nous suivons un SCRUM maison, ajusté régulièrement selon nos besoins. Nous discutons ensemble de nos priorités et nous les répartissons à chaque sprint selon les profils et envies de chacun·e.</p>
<p><strong>Vous participerez :</strong></p>
<ul>
<li>
<p>Au développement back de j360 et son back-end (Python/Django, PostgreSQL, ElasticSearch).</p>
</li>
<li>
<p>Aux scripts de collecte de données (Python/Scrapy).</p>
</li>
<li>
<p>À la relecture de code et l’accompagnement vos collègues en leur fournissant du mentorat sur les bonnes pratiques, l’architecture, les design patterns, etc.</p>
</li>
</ul>
<p><strong>En fonction de vos centres d’intérêts :</strong></p>
<ul>
<li>
<p>Au développement front de l’application j360 (Vue3/Quasar/Typescript).</p>
</li>
<li>
<p>Au déploiement des applications (Docker/Docker-Compose, Ansible) et intégration des services R&amp;D (Gitlab CI).</p>
</li>
<li>
<p>À la réflexion produit, analyse technique et à la définition des priorités de l’entreprise (Trello).</p>
</li>
<li>
<p>À l’ajustement de nos méthodes de travail au sein de l’équipe et de l’entreprise.</p>
</li>
</ul>
<p><strong>Avantages :</strong></p>
<ul>
<li>
<p>Horaires flexibles - RTT - Titres-restaurant - Participation au transport - Épargne salariale - Plan d’intéressement et plan épargne entreprise</p>
</li>
<li>
<p>Télétravail/présentiel</p>
</li>
<li>
<p>Statut cadre en fonction du diplôme/l’expérience (Syntec)</p>
</li>
</ul>
<p><strong>Processus de recrutement :</strong></p>
<p>Les candidatures “one clic” ne sont pas regardées. Si vous prenez le temps de faire une candidature personnalisée, nous l’étudierons; sinon ne perdez pas votre temps, envoyez votre candidature à une ESN car on a pas de baby foot.</p>
<ul>
<li>
<p>CV + présentation de vous et de ce qui vous intéresse à adresser par mail à job @ octopusmind.info</p>
</li>
<li>
<p>Vous pouvez illustrer vos compétences techniques avec des exemples de projets ou passer notre test technique.</p>
</li>
<li>
<p>Echanges et précisions par mail ou téléphone</p>
</li>
<li>
<p>Entretien dans nos bureaux à Nantes</p>
</li>
<li>
<p>Offre (salaire en fonction de l’expérience/niveau)</p>
</li>
</ul>
<p><strong>SVP pas de démarchage pour de l’outsouring ou cabinet RH, merci</strong></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/developpeur-se-python-fullstack-nantes/2932">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>f.oliveau</name>
        </author>
    </entry>
    <entry>
        <title>Cloud et DevOps : Les enjeux clés à l’horizon 2026</title>
        <link href="https://bearstech.com/blog/cloud-et-devops-les-enjeux-cles-lhorizon-2026" />
        <id>https://bearstech.com/blog/cloud-et-devops-les-enjeux-cles-lhorizon-2026</id>
        <updated>2026-02-05T14:09:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>Cloud et DevOps : Les enjeux clés à l’horizon 2026</title>
        <link href="https://bearstech.com/societe/blog/cloud-et-devops-les-enjeux-cles-lhorizon-2026" />
        <id>https://bearstech.com/societe/blog/cloud-et-devops-les-enjeux-cles-lhorizon-2026</id>
        <updated>2026-02-05T14:09:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>EuroPython 2026 − du 13 au 19 juillet</title>
        <link href="https://discuss.afpy.org/t/europython-2026-du-13-au-19-juillet/2929" />
        <id>https://discuss.afpy.org/t/europython-2026-du-13-au-19-juillet/2929</id>
        <updated>2026-02-04T11:28:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>L’<a href="https://ep2026.europython.eu/">EuroPython 2026</a> a lieu à Cracovie du 13 au 19 juillet <img alt=":poland:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/poland.png?v=15" title=":poland:" width="20"/>.</p>
<p>L’<a href="https://programme.europython.eu/europython-2026/">appel à propositions</a> est ouvert jusqu’au 15 février et il y a un programme de <a href="https://ep2026.europython.eu/mentorship/">mentorship</a> pour aider à structurer / répéter si besoin.</p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/europython-2026-du-13-au-19-juillet/2929/1" style="font-weight: bold; font-size: 1.1em;">EuroPython 2026</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">July 13, 2026 9:00 AM (Europe/Paris) → July 19, 2026 6:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://ep2026.europython.eu/</td>
</tr>
</tbody></table>
<p><small>5 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/europython-2026-du-13-au-19-juillet/2929">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Construire un C&amp;C basique en python/FORTH au dessus de MQTT</title>
        <link href="https://linuxfr.org/users/jul/journaux/construire-un-c-c-basique-en-python-forth-au-dessus-de-mqtt" />
        <id>https://linuxfr.org/users/jul/journaux/construire-un-c-c-basique-en-python-forth-au-dessus-de-mqtt</id>
        <updated>2026-02-02T13:56:58Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-introduction">Introduction</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-ingr%C3%A9dients">Ingrédients</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-la-pi%C3%A8ce-de-r%C3%A9sistance">La pièce de résistance</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-la-recette">La recette</a></li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-diverses-questions-r%C3%A9ponses">Diverses Questions Réponses</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-un-forth-dans-la-boucle-%C3%A9tait-il-n%C3%A9cessaire">Un forth dans la boucle était il nécessaire ?</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-un-vrai-command--control-pr%C3%A9f%C3%A9rerait-un-protocole-plus-passe-partout-comme-https-pour-%C3%AAtre-moins-visible">Un vrai command &amp; control préférerait un protocole plus passe partout comme <em>https</em> pour être moins visible</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-et-si-je-voulais-s%C3%A9curiser">Et si je voulais sécuriser ?</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-o%C3%B9-est-larborescente-compl%C3%A8te-du-projet-il-manque-les-plugins-de-mesure">Où est l'arborescente complète du projet il manque les plugins de mesure ?</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-mais-cest-b%C3%AAte-en-fait">Mais c'est bête en fait…</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-des-id%C3%A9es-de-futurs">Des idées de futurs ?</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-les-sorties-actuellement-ressemblent-au-format-dentr%C3%A9e--cest-suspect-non">Les sorties actuellement ressemblent au format d'entrée … C'est suspect non ?</a></li>
</ul>
</li>
</ul>
<h2 id="toc-introduction">Introduction</h2>
<p>Qui n'a pas rêvé de faire sa console de pirates qui contrôle ses agents au doigt et à l'œil traditionnellement sur IRC ?</p>
<p>C'est le principe d'un <a href="https://en.wikipedia.org/wiki/Botnet#Command_and_control">Control &amp; Command</a> parfois appelé C&amp;C pour les botnets. Mais ici, on en fait un éducationnel.</p>
<p>Il s'agit de piloter des agents à distance en leur envoyant des commandes sur un BUS qui résulte dans des actions prédéfinies comme :<br/>
- arrêtes toi, <br/>
- reprends, <br/>
- dis si tu es présent et en vie …</p>
<p>Ci-suit un petit exemple en python de l'implémentation d'une telle logique en moins de 100 lignes de codes</p>
<h2 id="toc-ingrédients">Ingrédients</h2>
<p>Cette recette nécessite : python, et en dépendances : <em>paho-mqtt</em>, <em>confined</em>, ainsi qu'un serveur <a href="https://mosquitto.org/">MQTT</a> (mosquitto avec ses utilitaires en ligne de commande) correctement configurés.</p>
<h2 id="toc-la-pièce-de-résistance">La pièce de résistance</h2>
<p>Pour tout process que l'on veut piloter on va écrire du code python comme : </p>
<pre><code class="python"><span class="kn">import</span> <span class="nn">paho.mqtt.client</span> <span class="kn">as</span> <span class="nn">mqtt</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">time</span><span class="p">,</span> <span class="n">sleep</span>
<span class="kn">from</span> <span class="nn">confined</span> <span class="kn">import</span> <span class="n">parse</span><span class="p">,</span> <span class="n">Value</span><span class="p">,</span> <span class="n">pop</span>
<span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">Popen</span><span class="p">,</span><span class="n">PIPE</span>
<span class="kn">import</span> <span class="nn">pathlib</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">socket</span>

<span class="n">stack</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">client_id</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">gethostname</span><span class="p">()</span>
<span class="n">show_must_go</span> <span class="o">=</span> <span class="bp">False</span>

<span class="k">def</span> <span class="nf">on_connect</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">userdata</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">reason_code</span><span class="p">,</span> <span class="n">properties</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s2">"Connected with result code {reason_code}"</span><span class="p">)</span>
    <span class="n">client</span><span class="o">.</span><span class="n">subscribe</span><span class="p">(</span><span class="n">f</span><span class="s2">"BUS/{client_id}"</span><span class="p">)</span>
    <span class="n">client</span><span class="o">.</span><span class="n">subscribe</span><span class="p">(</span><span class="n">f</span><span class="s2">"BUS"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">on_lun</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="n">kw</span><span class="p">[</span><span class="s2">"ctx"</span><span class="p">][</span><span class="s2">"state"</span><span class="p">]</span><span class="o">=</span><span class="s2">"RAZ"</span>

<span class="k">def</span> <span class="nf">on_set_time_slice</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="n">kw</span><span class="p">[</span><span class="s2">"ctx"</span><span class="p">][</span><span class="s2">"time_slice"</span><span class="p">]</span><span class="o">=</span><span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">.</span><span class="n">float</span>


<span class="k">def</span> <span class="nf">on_ping</span><span class="p">(</span><span class="o">*</span><span class="n">a</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">global</span> <span class="n">client_id</span>
    <span class="n">client</span> <span class="o">=</span> <span class="n">kw</span><span class="p">[</span><span class="s2">"ctx"</span><span class="p">][</span><span class="s2">"client"</span><span class="p">]</span>
    <span class="n">client</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="s2">"RES"</span><span class="p">,</span> <span class="n">f</span><span class="s2">"'{client_id}':PONG"</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">on_sel</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">global</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">show_must_go</span>
    <span class="k">if</span> <span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">.</span><span class="n">str</span> <span class="o">==</span> <span class="n">client_id</span><span class="p">:</span>
        <span class="n">show_must_go</span> <span class="o">=</span> <span class="bp">True</span>

<span class="k">def</span> <span class="nf">on_unsel</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">global</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">show_must_go</span>
    <span class="k">if</span> <span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span><span class="o">.</span><span class="n">str</span> <span class="o">==</span> <span class="n">client_id</span><span class="p">:</span>
        <span class="n">show_must_go</span> <span class="o">=</span> <span class="bp">False</span>

<span class="k">def</span> <span class="nf">on_test</span><span class="p">(</span><span class="n">stack</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="s2">"Yo"</span><span class="p">)</span>


<span class="n">ctx</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
    <span class="n">cap</span><span class="o">=</span><span class="p">[</span><span class="s2">"www"</span><span class="p">,</span> <span class="s2">"forth"</span> <span class="p">],</span>
    <span class="n">time_slice</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
    <span class="n">dispatch</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span>
        <span class="n">lun</span><span class="o">=</span><span class="n">on_lun</span><span class="p">,</span>
        <span class="n">ping</span><span class="o">=</span><span class="n">on_ping</span><span class="p">,</span>
        <span class="n">sel</span><span class="o">=</span><span class="n">on_sel</span><span class="p">,</span>
        <span class="n">unsel</span><span class="o">=</span><span class="n">on_unsel</span><span class="p">,</span>
        <span class="n">tsset</span><span class="o">=</span><span class="n">on_set_time_slice</span><span class="p">,</span>
        <span class="n">_TEST</span><span class="o">=</span><span class="n">on_test</span><span class="p">,</span>
    <span class="p">),</span>
<span class="p">)</span>

<span class="k">def</span> <span class="nf">on_message</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">userdata</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
    <span class="k">global</span> <span class="n">stack</span><span class="p">,</span> <span class="n">ctx</span>
    <span class="n">ctx</span><span class="p">[</span><span class="s2">"client"</span><span class="p">]</span> <span class="o">=</span> <span class="n">client</span>
    <span class="n">client</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span>
        <span class="s2">"RES"</span><span class="p">,</span> 
        <span class="nb">str</span><span class="p">(</span><span class="n">parse</span><span class="p">(</span>
           <span class="n">ctx</span><span class="p">,</span>
           <span class="n">msg</span><span class="o">.</span><span class="n">payload</span><span class="o">.</span><span class="n">decode</span><span class="p">(),</span>
           <span class="n">data</span><span class="o">=</span><span class="n">stack</span><span class="p">,</span> 
           <span class="p">)</span>
        <span class="p">)</span>
    <span class="p">)</span>


<span class="n">mqttc</span> <span class="o">=</span> <span class="n">mqtt</span><span class="o">.</span><span class="n">Client</span><span class="p">(</span><span class="n">mqtt</span><span class="o">.</span><span class="n">CallbackAPIVersion</span><span class="o">.</span><span class="n">VERSION2</span><span class="p">,</span> <span class="n">client_id</span><span class="o">=</span><span class="n">client_id</span><span class="p">)</span>
<span class="n">mqttc</span><span class="o">.</span><span class="n">on_connect</span> <span class="o">=</span> <span class="n">on_connect</span>
<span class="n">mqttc</span><span class="o">.</span><span class="n">on_message</span> <span class="o">=</span> <span class="n">on_message</span>

<span class="n">mqttc</span><span class="o">.</span><span class="n">username</span> <span class="o">=</span> <span class="s2">"pub"</span>
<span class="n">mqttc</span><span class="o">.</span><span class="n">password</span><span class="o">=</span> <span class="s2">"pub"</span>
<span class="n">mqttc</span><span class="o">.</span><span class="n">tls_set</span><span class="p">(</span>
    <span class="n">keyfile</span><span class="o">=</span><span class="s2">"./cfg/pub.key"</span><span class="p">,</span>
    <span class="n">certfile</span><span class="o">=</span><span class="s2">"./cfg/pub.crt"</span><span class="p">,</span>
    <span class="n">ca_certs</span><span class="o">=</span><span class="s2">"./cfg/RootCA.crt"</span><span class="p">,</span>
    <span class="n">tls_version</span><span class="o">=</span><span class="mi">2</span>
<span class="p">)</span>
<span class="n">mqttc</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">"badass.home"</span><span class="p">,</span> <span class="mi">8883</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span>
<span class="n">mqttc</span><span class="o">.</span><span class="n">loop_start</span><span class="p">()</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="vm">__file__</span><span class="p">))</span>

<span class="n">plugins</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">"../plugin"</span><span class="p">)</span>

<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
    <span class="n">start</span> <span class="o">=</span> <span class="n">time</span><span class="p">()</span>
    <span class="k">if</span> <span class="n">show_must_go</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">plugins</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s2">"*_enabled"</span><span class="p">):</span>
            <span class="k">with</span> <span class="n">Popen</span><span class="p">([</span> <span class="n">p</span><span class="p">,</span>  <span class="p">],</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stdin</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">bufsize</span><span class="o">=</span><span class="mi">0</span><span class="p">,)</span> <span class="k">as</span> <span class="n">writer</span><span class="p">:</span>
                <span class="k">while</span> <span class="n">res</span> <span class="p">:</span><span class="o">=</span> <span class="n">writer</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">read</span><span class="p">():</span>
                    <span class="n">writer</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
                    <span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">res</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
                        <span class="n">mqttc</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="n">f</span><span class="s2">"DATA/{client_id}"</span><span class="p">,</span> <span class="n">msg</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
        <span class="n">mqttc</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="s2">"DATA/"</span><span class="p">,</span> <span class="n">f</span><span class="s2">"{client_id}:core.processing_time:{time()-start}:GAUGE"</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">time</span><span class="p">()</span> <span class="o">-</span><span class="n">start</span> <span class="o">&lt;</span> <span class="n">ctx</span><span class="p">[</span><span class="s2">"time_slice"</span><span class="p">]:</span>
            <span class="n">sleep</span><span class="p">(</span><span class="n">ctx</span><span class="p">[</span><span class="s2">"time_slice"</span><span class="p">]</span> <span class="o">-</span> <span class="p">(</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">start</span><span class="p">))</span></code></pre>
<p>Le client est en mode parano : TLS activé avec login/pass enforcé coté serveur par MQTT.</p>
<p>On va définir 2 commandes :</p>
<p>pub.sh</p>
<pre><code class="bash"><span class="ch">#!/usr/bin/env bash</span>
<span class="nv">HERE</span><span class="o">=</span><span class="k">$(</span> dirname <span class="nv">$0</span> <span class="k">)</span>
<span class="nb">pushd</span> <span class="nv">$HERE</span>

mosquitto_pub --cert ../cfg/4711.crt --key ../cfg/4711.key --cafile ../cfg/RootCA.crt -h badass.home -t BUS -u <span class="m">4711</span> -P <span class="m">4711</span> -m <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
<span class="nb">popd</span></code></pre>
<p>qui publie en MQTT sur un canal BUS</p>
<p>et <br/>
listen.sh</p>
<pre><code class="bash"><span class="ch">#!/usr/bin/env bash</span>

<span class="nv">HERE</span><span class="o">=</span><span class="k">$(</span> dirname <span class="nv">$0</span> <span class="k">)</span>
<span class="nb">pushd</span> <span class="nv">$HERE</span>
mosquitto_sub -h badass.home -t RES/# <span class="p">&amp;</span>
mosquitto_sub -h badass.home -t DATA/# <span class="p">&amp;</span>
<span class="nb">popd</span></code></pre>
<h2 id="toc-la-recette">La recette</h2>
<p>Pour pinger votre agent il vous suffit de faire</p>
<p><em>pub.sh PING</em> </p>
<p>ce qui répond</p>
<p><em>'badass':PONG</em></p>
<p>Pour tester la fonction de test locale : </p>
<p><em>pub.sh _TEST</em></p>
<p>Normalement sur sortie standard du process python vous pouvez lire : 'Yo'.</p>
<p><em>pub.sh "'badass': SEL"</em></p>
<p>La sortie de LISTEN devrait montrer des lignes comme suit:</p>
<pre><code class="erlang"><span class="nn">badass</span><span class="p">:</span><span class="n">cpu</span><span class="p">.</span><span class="nn">load</span><span class="p">:</span><span class="mi">1</span><span class="p">.</span><span class="mi">39</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">stat</span><span class="p">.</span><span class="nn">procs_running</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">stat</span><span class="p">.</span><span class="nn">procs_blocked</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">stat</span><span class="p">.</span><span class="nn">intr</span><span class="p">:</span><span class="mi">235643164</span><span class="p">:</span><span class="nv">DERIVE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">stat</span><span class="p">.</span><span class="nn">ctxt</span><span class="p">:</span><span class="mi">474453646</span><span class="p">:</span><span class="nv">DERIVE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">stat</span><span class="p">.</span><span class="nn">processes</span><span class="p">:</span><span class="mi">237036</span><span class="p">:</span><span class="nv">DERIVE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">processes</span><span class="p">:</span><span class="mi">320</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">uninterruptible</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">runnable</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">sleeping</span><span class="p">:</span><span class="mi">256</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">idle</span><span class="p">:</span><span class="mi">62</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">stopped</span><span class="p">:</span><span class="mi">0</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">paging</span><span class="p">:</span><span class="mi">0</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">dead</span><span class="p">:</span><span class="mi">0</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">ps</span><span class="p">.</span><span class="nn">zombie</span><span class="p">:</span><span class="mi">0</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">files</span><span class="p">.</span><span class="nn">opened</span><span class="p">:</span><span class="mi">17184</span><span class="p">:</span><span class="nv">GAUGE</span>
<span class="nn">badass</span><span class="p">:</span><span class="n">core</span><span class="p">.</span><span class="nn">processing_time</span><span class="p">:</span><span class="mi">0</span><span class="p">.</span><span class="mi">039983272552490234</span><span class="p">:</span><span class="nv">GAUGE</span></code></pre>
<p>Qui sont le résultat de l'enclenchement de la mesure qui se fait toutes les 10 secondes par défaut</p>
<p><em>pub.sh "20: TSSET"</em></p>
<p>Passe les mesures à 20 secondes d'écart. </p>
<p><em>pub.sh "'badass': UNSEL"</em></p>
<p>Arrête les mesures.</p>
<h2 id="toc-diverses-questions-réponses">Diverses Questions Réponses</h2>
<h3 id="toc-un-forth-dans-la-boucle-était-il-nécessaire">Un forth dans la boucle était il nécessaire ?</h3>
<p>Non.</p>
<p>Mais il se trouve que <a href="https://github.com/jul/confined">j'en ai un en stock</a> et que je rêvais de l'utiliser pour faire des tâches innocentes (principalement du templating).</p>
<p>Il est pas utilisé, mais disons que si vous faisiez :</p>
<p><em>pub.sh "2: 2: ADD"</em></p>
<p>en sortie vous auriez autant de <em>4:</em> qu'il y a d'agents connectés sur le BUS.</p>
<p>Vous avez de base une calculette 4 opérations distribuées en prime.</p>
<h3 id="toc-un-vrai-command--control-préférerait-un-protocole-plus-passe-partout-comme-https-pour-être-moins-visible">Un vrai command &amp; control préférerait un protocole plus passe partout comme <em>https</em> pour être moins visible</h3>
<p><a href="http://www.steves-internet-guide.com/mqtt-websockets/">Ça tombe bien paho-mqtt et mosquito permettent de passer en websocket</a> :)</p>
<h3 id="toc-et-si-je-voulais-sécuriser">Et si je voulais sécuriser ?</h3>
<p><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_grundlagen/17769201803.html&amp;id=">MQTT le permet</a> avec des ACL par sujets.</p>
<h3 id="toc-où-est-larborescente-complète-du-projet-il-manque-les-plugins-de-mesure">Où est l'arborescente complète du projet il manque les plugins de mesure ?</h3>
<p><a href="https://github.com/jul/FAIM/tree/main/plugin">Les plugins sont ici</a></p>
<h3 id="toc-mais-cest-bête-en-fait">Mais c'est bête en fait…</h3>
<p>C'est pas faux, c'est pour ça que je sais pas quoi <a href="https://linuxfr.org/users/jul/journaux/j-ai-des-noeuds-au-cerveau-je-ne-sais-pas-comment-continuer">faire avec ce « projet »</a></p>
<p>Trop petit pour être un projet, ultra dur à tester, mais assez rigolo pour être utile</p>
<h3 id="toc-des-idées-de-futurs">Des idées de futurs ?</h3>
<p>Un projet « Bus Of Things » (BOT) qui standardiserait les commandes envoyées et leurs API pour faire comme une sorte d'ansible.</p>
<p>Une logique d'IPC/messaging générique pour des systèmes distribués (inclurais la gestion de process &amp; co).</p>
<p>Un FORTH qui verrait toute fonction/agent comme reliée à un BUS MQTT et pour lequel les messages serait du FORTH qui agirait sur la fonction que s'appelerio objective FORTH. (Ça implique de sacrément développé la partie langage).</p>
<p>Pleins d'idées, trop d'idées …</p>
<h3 id="toc-les-sorties-actuellement-ressemblent-au-format-dentrée--cest-suspect-non">Les sorties actuellement ressemblent au format d'entrée … C'est suspect non ?</h3>
<p>Oui, j'ai envie de tester de laisser l'orchestrateur accepter des injections de code depuis les agents. Ex légitime, quand une sonde de mesure est en OVERRUN (trop de temps passé à mesurer comparé à une cadence attendue) qu'elle puisse changer la « clock » avec TSSET de l'orchestrateur.</p>
<p>J'ai envie d'expérimenter des systèmes scheduler less où chaque agent peut devenir le contrôleur et prendre la main et/ou modifier l'orchestrateur qui envoie les commandes.</p>
<div><a href="https://linuxfr.org/users/jul/journaux/construire-un-c-c-basique-en-python-forth-au-dessus-de-mqtt.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142157/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jul/journaux/construire-un-c-c-basique-en-python-forth-au-dessus-de-mqtt#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Jul</name>
        </author>
    </entry>
    <entry>
        <title>Clawdbot [moltbot] rend la Silicon Valley totalement accro</title>
        <link href="https://linuxfr.org/users/pas_pey/liens/clawdbot-moltbot-rend-la-silicon-valley-totalement-accro" />
        <id>https://linuxfr.org/users/pas_pey/liens/clawdbot-moltbot-rend-la-silicon-valley-totalement-accro</id>
        <updated>2026-01-31T22:46:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.clubic.com/actualite-597343-pourquoi-clawdbot-est-en-train-de-rendre-la-silicon-valley-totalement-accro.html">https://www.clubic.com/actualite-597343-pourquoi-clawdbot-est-en-train-de-rendre-la-silicon-valley-totalement-accro.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142140/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/pas_pey/liens/clawdbot-moltbot-rend-la-silicon-valley-totalement-accro#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>pas_pey</name>
        </author>
    </entry>
    <entry>
        <title>Profileur mémoire MALT 1.6.0 et support de Python</title>
        <link href="https://linuxfr.org/news/profileur-memoire-malt-1-6-0-et-support-de-python" />
        <id>https://linuxfr.org/news/profileur-memoire-malt-1-6-0-et-support-de-python</id>
        <updated>2026-01-30T13:55:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><h2 id="toc-malt-cest-quoi">MALT c'est quoi ?</h2>
<p>L'optimisation est une activité connue de bien des développeurs, fouiller, chercher dans son code, pour, peut être, gagner un peu de performance (beaucoup, parfois). Dans cette tâche ardue, face à des codes grandissants, massifs, utilisant de nombreuses bibliothèques externes, un outil central dans ce travail de fourmi : <strong>le profileur</strong>.</p>
<p>Le profileur fait partie des outils importants pour le développeur qui se soucie des ressources qu'il utilise. Il lui permet de chercher les points chauds dans son code, comprendre le cout de chaque fonction, chaque ligne implémentée. Bien des outils s'intéressent à une chose : bien utiliser votre processeur.</p>
<p>Mais que se passe-t-il si vous rencontrez des difficultés avec l'utilisation de votre <strong>mémoire</strong> ? Si vous pensez mal utiliser la fonction <code>malloc()</code> du C ou l'opérateur <code>new</code> du C++ ? Si vous avez oublié qu'une de vos variables globales occupe <strong>10 Go</strong> (surtout en Fortran) ?</p>
<p>Publié il y a quelques années <a href="https://memtt.github.io/malt/">MALT</a> (licence CeCILL-C) permet de répondre à la question en cherchant toutes les <strong>allocations mémoires</strong> faites par votre code. Cet outil avait fait l'objet d'un article sur LinuxFR en 2018 lors de sa mise en open source : <a href="https://linuxfr.org/news/profileurs-memoire-malt-et-numaprof">Profileurs mémoire MALT et NUMAPROF</a>.</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116923" hreflang="en" title="https://memtt.github.io/">Site officiel de MALT</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/116924" hreflang="en" title="https://github.com/memtt/malt">Dépôt github</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/116925" hreflang="fr" title="https://linuxfr.org/news/profileurs-memoire-malt-et-numaprof">Premier article LinuxFR sur MALT</a></li></ul><div><h2 id="toc-versions-160">Versions 1.6.0</h2>
<h3 id="toc-avancées">Avancées</h3>
<p>Depuis, cet outil fait son chemin avec l'ajout du support de <strong>Rust</strong> ainsi que nombreuses corrections et ajouts tels que la possibilité de dumper le profile mémoire juste avant que le système ne soit plein.</p>
<pre><code class="sh">malt -o dump:on-sys-full-at<span class="o">=</span><span class="m">80</span>% -o watch-dog<span class="o">=</span><span class="nb">true</span> ./mon_programme

<span class="c1"># également :</span>
<span class="c1">#  -o dump:on-app-using-rss=10G</span>
<span class="c1">#  -o dump:on-app-using-virt=80%</span>
<span class="c1">#  -o dump:on-app-using-req=500M</span></code></pre>
<p>La possibilité de suivre les appels à <strong>mmap</strong>, <strong>mremap</strong>, <strong>munmap</strong> si vous les appelez directement dans votre code au lieu de laisser <strong>malloc</strong> faire son travail.</p>
<h3 id="toc-support-de-python">Support de python</h3>
<p>MALT a initialement été développé dans le contexte du <a href="https://fr.wikipedia.org/wiki/calcul%20%C3%A0%20haute%20performance">calcul à haute performance</a> — HPC (High Performance Computing) donc surtout pour le C / C++ / Fortran / Rust.</p>
<p>Dans la communauté scientifique, nous voyons dans les laboratoires de plus en plus fleurir l'usage d'un langage à priori bien éloigné de nos prérogatives de performances : <a href="https://www.python.org/">Python</a>.</p>
<p>Dans un cadre de calcul scientifique, il est souvent utilisé plutôt comme un wrapper permettant d'appeler et d'orchestrer des bibliothèques en C /C++ / Fortran, elles, performantes. Quoi que l'usage amène aussi à l'écrire de certaines parties du code en Python grâce à <a href="https://numpy.org/">Numpy</a> ou <a href="https://numba.pydata.org/">Numba</a> pour accéléré la partie calcule sur des tableaux ou autres frameworks d'exploitation des GPU.</p>
<p>La version <strong>1.6.0 de MALT</strong> vient d'ajouter le support (encore quelque peu <strong>expérimental</strong>) natif de Python permettant d'analyser un code <strong>pur python</strong> ou <strong>mix Python / C / C++…</strong>. Il s'agit pour l'instant de la <strong>première version</strong> avec ce support, il reste donc du travail.</p>
<p>Sont supportés les versions Python <strong>supérieures à 3.11</strong> ainsi que les environnements <strong>Conda</strong> / <strong>Anaconda</strong> / <strong>Venv</strong>. À l'heure de rédaction de cet article, cela comprend les versions <strong>3.11</strong> à <strong>3.14</strong>.</p>
<p>MALT étant orienté C / C++, il ne supporte que <strong>Linux</strong> comme système d'exploitation. (<em>NdM:</em> la causalité évoquée ici devrait faire réagir des développeurs d'autres systèmes libres notamment :))</p>
<h3 id="toc-utilisation-sur-python">Utilisation sur Python</h3>
<p>Si la commande <code>malt</code> fonctionne parfaitement, il est recommandé d'utiliser le wrapper <code>malt-python</code> qui adapte quelques configurations spécifiques à Python non encore automatiques.</p>
<pre><code class="sh">malt-python ./script.py

<span class="c1"># équivalent à </span>
malt --profile python-default ./script.py

<span class="c1"># liste des profiles</span>
malt --profile <span class="nb">help</span>

<span class="c1"># Afficher le profile</span>
malt-webview ./malt-script-py-6889.json</code></pre>
<h3 id="toc-profilage-rapide">Profilage rapide</h3>
<p>Notons que l'<strong>overhead</strong> de MALT est important en Python du fait du large nombre d'allocations générées par ce langage et de la méthode de résolution des piles d'appels pour retrouver les lignes dans votre code. Ces détails d'analyse peuvent être désactivés via :</p>
<pre><code class="sh"><span class="c1"># Désactivé complète de l'analyse des piles</span>
malt-python -p python-no-stack ./my_script.py

<span class="c1"># Analyse des piles par "sampling"</span>
malt-python -p python-sampling ./my_script.py</code></pre>
<h3 id="toc-nouvelle-interface">Nouvelle interface</h3>
<p>La version <strong>1.6.0</strong> arrive également avec une nouvelle interface graphique avec un code remis à jour<br/>
par rapport à sa version originale vieillissante.</p>
<p><img alt="Capture annotation python" src="https://img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6d656d74742f6d616c742f7261772f6d61737465722f73637265656e73686f742e706e67/screenshot.png" title="Source : https://github.com/memtt/malt/raw/master/screenshot.png"/></p>
<h3 id="toc-profil-statique">Profil statique</h3>
<p>Pour ceux qui voudraient échanger les profils avec d'autres sur d'autres OS, il est possible depuis la <strong>1.6.0</strong> de générer une version statique des pages de l'interface (hors annotation des sources et arbre d'appel navigable) via :</p>
<pre><code class="sh"><span class="c1"># Toues les pages possible en statique</span>
malt-webview -static ./report malt-progr-123456.json

<span class="c1"># Seulement la page de résumé.</span>
malt-webview -static-summary ./report malt-progr-123456.json</code></pre>
<h2 id="toc-installation">Installation</h2>
<p>MALT n'est pas encore disponible dans les distributions classiques, vous devez donc le compiler et l'installer à la main. Le nombre réduit de dépendances obligatoires en fait un outil relativement facile à installer.</p>
<p>On trouvera la procédure dans la <a href="https://memtt.github.io/malt/doc/1.6.0/start/installation.html">documentation</a> du projet.</p>
<h2 id="toc-documentation">Documentation</h2>
<p>La documentation a été complètement ré-écrite et disponible sur le site officiel : <a href="https://memtt.github.io/malt/doc/v1.6.0">documentation</a>.</p>
<h2 id="toc-outils-similaires-pour-python">Outils similaires pour Python</h2>
<p>Découvrir un outil est aussi l'occasion d'en découvrir d'autres. Restons dans le monde du <strong>Python</strong>, si MALT ne vous convient pas vous trouverez peut-être votre bonheur avec les <strong>outils suivants</strong> et <strong>complémentaires</strong> à MALT et eux totalement dédiés au Python toujours pour la <strong>mémoire</strong> :</p>
<ul>
<li>
<a href="https://bloomberg.github.io/memray/">Memray</a> (Apache Public License 2)</li>
<li>
<a href="https://github.com/plasma-umass/scalene">Scalene</a> (Apache Public License 2)</li>
</ul>
<p><strong>MALT</strong> se positionne par rapport aux deux présentés en apportant une analyse fine en <strong>annotant</strong> tout <strong>le source code</strong> de l'application. Il offre également une analyse des <strong>variables globales</strong> et <strong>TLS</strong> coté C/C++/Fortran/Rust.</p>
</div><div><a href="https://linuxfr.org/news/profileur-memoire-malt-1-6-0-et-support-de-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/142101/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/profileur-memoire-malt-1-6-0-et-support-de-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Sébastien Valat,Benoît Sibaud,Pierre Jarillon</name>
        </author>
    </entry>
    <entry>
        <title>Développeur Full Stack - OTERIA</title>
        <link href="https://discuss.afpy.org/t/developpeur-full-stack-oteria/2926" />
        <id>https://discuss.afpy.org/t/developpeur-full-stack-oteria/2926</id>
        <updated>2026-01-29T10:30:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <blockquote>
<p>(Full disclosure : je travaille à Oteria en tant que prof de Python et de C, je relaie ici une offre d’emploi émise par l’école. )</p>
</blockquote>
<h1><a class="anchor" href="https://discuss.afpy.org#p-12621-dveloppeur-full-stack-oteria-1" name="p-12621-dveloppeur-full-stack-oteria-1"></a>Développeur Full Stack - OTERIA</h1>
<p>CDI – Gennevilliers (92) - Métro Gabriel Peri - Ligne 13 - Début: ASAP - autour de 40k€ brut annuels selon profil et expérience</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-propos-doteria-2" name="p-12621-propos-doteria-2"></a>À propos d’OTERIA</h2>
<p>OTERIA est une école d’excellence dédiée aux métiers de la cybersécurité.<br/>
Elle forme des profils solides techniquement, engagés, capables d’avoir un impact réel et durable dans l’écosystème cyber.</p>
<p>Dans un contexte de marché du travail tendu, de révolution de l’IA et de transformation profonde de l’enseignement supérieur, nous sommes convaincus que les écoles ont une responsabilité :<br/>
former des jeunes talents capables de maîtriser des technologies de pointe, leur sécurité et l’IA, grâce à une pédagogie exigeante, ancrée dans le réel et fondée sur l’émulation humaine.</p>
<p>OTERIA n’est pas uniquement un programme de formation. C’est une communauté, une culture, et une vision exigeante de l’éducation, tournée vers l’action, la transmission et le réel.</p>
<p>L’école accueille aujourd’hui 300 étudiants, de Bac+1 à Bac+5, et s’appuie sur une équipe de 8 personnes, engagées au quotidien dans le projet éducatif et le développement de l’école. Nous faisons le choix de rester une structure à taille humaine, afin de préserver l’agilité, la proximité et la capacité d’adaptation qui font la force d’OTERIA, tant dans sa pédagogie que dans son fonctionnement, tout en capitalisant pleinement sur l’IA pour gagner en efficacité et en impact.</p>
<p>Nous lançons le développement d’une nouvelle plateforme pédagogique interne ambitieuse, pensée comme un <strong>environnement d’apprentissage intelligent</strong>, augmentant le présentiel grâce au numérique et à l’IA.</p>
<p>Cette plateforme n’est ni un LMS classique, ni un MOOC. C’est un outil pédagogique vivant, conçu pour :</p>
<ul>
<li>aider les professeurs à améliorer continuellement leurs cours,</li>
<li>offrir aux étudiants des expériences d’apprentissage motivantes,</li>
<li>capitaliser sur ce qui se passe réellement en cours,</li>
<li>et créer une communauté technique autour de la plateforme.</li>
</ul>
<p>C’est dans ce contexte que nous recrutons un développeur full stack.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-les-missions-3" name="p-12621-les-missions-3"></a>LES MISSIONS</h2>
<p>Au sein de l’équipe, vous prendrez en charge le développement de l’écosystème numérique de l’école. Votre rôle central consistera à concevoir et développer la première version du KERNEL, l’environnement pédagogique propriétaire d’OTERIA.</p>
<p>Pour ce projet, vous bâtirez une architecture backend modulaire en FastAPI couplée à une base SQL. Vous devrez traduire techniquement le concept d’« Expériences Pédagogiques » et développer une structure API-First intégrant des services d’IA internes pour la génération de contenu et l’analyse de données. Vous assurerez également la mise en place d’une interface unifiée et « mobile-friendly » pour les professeurs et les étudiants.</p>
<p>En parallèle de ce projet structurant, vous interviendrez sur l’ensemble des chantiers techniques de l’école. Vous participerez notamment au développement d’outils internes destinés à soutenir les différentes équipes (comme le marketing ou les opérations).</p>
<p>Vous contribuerez à l’automatisation des processus métiers (via des outils comme n8n ou du scripting) et assurerez la maintenance évolutive des applications existantes. Votre mission inclura également une veille technique pour garantir la robustesse et la sécurité de l’infrastructure, en cohérence avec les exigences d’une école spécialisée en cybersécurité.</p>
<p>Enfin, vous interviendrez en tant que référent pédagogique sur les enseignements liés au développement, et aurez l’opportunité de concevoir, animer et faire évoluer les cours de développement, ainsi que de produire des contenus pédagogiques structurants, notamment sous forme de projets applicatifs destinés aux étudiants.</p>
<p>Le KERNEL a vocation à devenir un actif central de l’école : un socle technologique structurant, au cœur des usages pédagogiques, techniques et communautaires d’OTERIA — une forme d’« OS » de l’école.</p>
<p>À mesure que la plateforme montera en charge (usages, utilisateurs, contributions étudiantes, intégrations IA), le rôle pourra naturellement évoluer vers des responsabilités élargies : structuration de la vision technique long terme, pilotage de la scalabilité et de la robustesse de la plateforme, encadrement de contributeurs (internes, étudiants, prestataires), prise de rôle de <strong>Lead Developer / référent architecture du produit</strong>.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-comptences-4" name="p-12621-comptences-4"></a>Compétences</h2>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12621-techniques-5" name="p-12621-techniques-5"></a>Techniques</h3>
<ul>
<li>Développement Backend : Maîtrise approfondie de Python et du framework FastAPI pour construire une architecture performante et modulaire.</li>
<li>Base de données : Expertise en SQL et en modélisation de données.</li>
<li>Architecture API-First : Capacité à concevoir une API documentée et sécurisée, destinée à alimenter l’interface web et, à terme, une application mobile native.</li>
<li>Intégration IA : Expérience technique dans l’intégration d’APIs d’Intelligence Artificielle local pour des fonctionnalités de génération de contenu et d’analyse de données.</li>
<li>Frontend &amp; Mobile : Compétence en développement d’interfaces web responsives (Mobile-friendly), respectant la contrainte d’une interface unique pour les vues “Professeur” et “Étudiant”.</li>
</ul>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12621-professionnelles-mthodologie-6" name="p-12621-professionnelles-mthodologie-6"></a>Professionnelles &amp; Méthodologie</h3>
<ul>
<li>Gestion de projet technique : Capacité à respecter le périmètre d’un MVP (Minimum Viable Product) en se concentrant sur les fonctionnalités critiques (création, diffusion, évaluation) et en écartant les développements hors-scope.</li>
<li>Exigence qualité : Rigueur dans l’écriture du code et la documentation (usage de Gitlab Interne pour mise à disposition Open Source aux étudiants), en cohérence avec le positionnement d’excellence d’OTERIA dans le domaine de la cybersécurité.</li>
<li>Collaboration : Aptitude à travailler au sein d’une équipe opérationnelle de 8 personnes et à dialoguer avec des profils non-techniques (équipe pédagogique) pour ajuster les fonctionnalités.</li>
</ul>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12621-atouts-apprcis-7" name="p-12621-atouts-apprcis-7"></a>Atouts appréciés</h3>
<ul>
<li>Expérience avec les outils d’automatisation de workflow (type n8n / make).</li>
<li>Appétence pour la pédagogie et le contexte d’une école.</li>
</ul>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-lenvironnement-de-travail-8" name="p-12621-lenvironnement-de-travail-8"></a>L’environnement de travail</h2>
<ul>
<li>Présence sur le campus de l’école:
<ul>
<li>c’est là que se passent les échanges clés,</li>
<li>c’est là que vivent les usages réels,</li>
<li>c’est là que le projet prend du sens.</li>
</ul>
</li>
<li>Télétravail <strong>occasionnel</strong></li>
<li>Contact direct avec :
<ul>
<li>Le responsable technique de l’école</li>
<li>le directeur général,</li>
<li>les professeurs,</li>
<li>les étudiants.</li>
</ul>
</li>
</ul>
<p><img alt=":backhand_index_pointing_right:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/backhand_index_pointing_right.png?v=15" title=":backhand_index_pointing_right:" width="20"/> La plateforme n’est pas un projet “en chambre”, elle se construit sur le terrain.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-ce-que-nous-recherchons-avant-tout-9" name="p-12621-ce-que-nous-recherchons-avant-tout-9"></a>Ce que nous recherchons avant tout</h2>
<p>Nous recherchons une personne engagée, curieuse et motivée, désireuse de s’investir dans un environnement où le projet technique a un sens pédagogique fort.</p>
<p>Le candidat devra :</p>
<ul>
<li>manifester un intérêt réel pour le monde de l’enseignement, et plus largement pour les enjeux de transmission des savoirs ;</li>
<li>être sensible aux questions de pédagogie, d’impact et d’amélioration continue, au-delà de la seule dimension technique ;</li>
<li>apprécier le fait de travailler sur un produit utilisé en conditions réelles, dont le code est appelé à être lu, compris, challengé et enrichi par d’autres — notamment par des étudiants ;</li>
<li>faire preuve d’un esprit d’ouverture, tant dans ses choix techniques que dans sa manière de collaborer, documenter et partager.</li>
</ul>
<p>Nous attachons plus d’importance à la qualité du raisonnement, à la capacité à apprendre et à s’adapter, qu’à un empilement de technologies ou à un profil strictement senior.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-rmunration-10" name="p-12621-rmunration-10"></a>Rémunération</h2>
<p>Rémunération selon profil et expérience (autour de 40k€ brut annuel) en cohérence avec le stade actuel du projet et la taille de la structure. Le poste est conçu comme une trajectoire d’évolution : la montée en compétences, l’élargissement des responsabilités et la prise de rôle structurants sur la plateforme ont vocation à s’accompagner d’une revalorisation progressive.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-ressources-et-moyens-disposition-11" name="p-12621-ressources-et-moyens-disposition-11"></a>Ressources et moyens à disposition</h2>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12621-ressources-techniques-12" name="p-12621-ressources-techniques-12"></a>Ressources techniques</h3>
<ul>
<li>Infrastructures de l’école (serveurs, capacités GPU, réseau) adaptées aux besoins du projet et aux usages liés à l’IA.</li>
<li>Mise à disposition des outils de développement nécessaires, incluant notamment des licences professionnelles (Cursor ou équivalent).</li>
<li>Possibilité de s’appuyer ponctuellement sur une agence spécialisée en UI/UX pour la conception et le développement des interfaces front-end, afin de garantir une expérience utilisateur de qualité.</li>
</ul>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12621-ressources-humaines-13" name="p-12621-ressources-humaines-13"></a>Ressources humaines</h3>
<ul>
<li><strong>Les étudiants</strong>: Les étudiants d’Oteria, utilisateurs directs de la plateforme, constituent une ressource centrale à la fois pour recueillir des retours d’usage concrets et pour contribuer activement à l’amélioration continue de la plateforme, notamment au travers d’analyses techniques et d’audits de sécurité encadrés.</li>
<li><strong>Les professeurs</strong>:Le corps professoral d’Oteria est composé de plus de 80 experts professionnels couvrant l’ensemble des champs de l’informatique et de la cybersécurité offrant un cadre privilégié au développeur pour l’échange de bonnes pratiques, le conseil technique et la montée en compétence continue</li>
</ul>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-pourquoi-rejoindre-oteria-14" name="p-12621-pourquoi-rejoindre-oteria-14"></a>Pourquoi rejoindre OTERIA</h2>
<ul>
<li>Participer à un projet central pour une école de référence</li>
<li>Une forte liberté d’initiative et de construction pour construire une école d’avenir</li>
<li>Un environnement pédagogique pour monter en compétences aux côtés d’experts</li>
<li>Un projet éducatif aligné avec les enjeux technologiques et sociétaux actuels</li>
<li>Une communauté d’étudiants engagés, passionnés et moteurs</li>
<li>En vidéo ça donne ça: <a href="https://www.youtube.com/watch?v=zaMZEl86VSw">cérémonie de remise des diplômes</a></li>
</ul>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12621-pour-candidater-15" name="p-12621-pour-candidater-15"></a>Pour candidater:</h2>
<p>Envoyez votre CV, quelques lignes expliquant votre motivation, ainsi qu’un lien vers vos projets (GitHub / GitLab) à : <a href="mailto:contact@oteria.fr">contact@oteria.fr</a></p>
<p>Merci d’indiquer en objet du mail : « Candidature offre développeur », et de préciser votre point de contact avec OTERIA (étudiant, alumni, recommandation, candidature externe, etc.).</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/developpeur-full-stack-oteria/2926">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>CDI Dev Senior FullStack Back/Front/Ops - Nouvelle Aquitaine</title>
        <link href="https://discuss.afpy.org/t/cdi-dev-senior-fullstack-back-front-ops-nouvelle-aquitaine/2924" />
        <id>https://discuss.afpy.org/t/cdi-dev-senior-fullstack-back-front-ops-nouvelle-aquitaine/2924</id>
        <updated>2026-01-27T17:27:14Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Flovea recherche une personne pour un rôle de Developpeur fullstack senior</p>
<p><strong>Contexte</strong></p>
<p>Flovea, société leader dans les solutions de plomberie préfabriquée et connectée, recherche une personne pour un rôle de “développeur sénior” pour prendre en charge la maintenance et l’évolution de sa solution Predictive Flowbox, solution de gestion de réseaux d’eau dans le but d’économiser de l’eau, de l’argent et de protéger les bâtiments contre les fuites et les dégâts des eaux. Flovea est basé à Saint Paul Lès Dax (Landes, à proximité de Dax).</p>
<p>La personne sera en charge du développement, du déploiement et de la gestion de l’infrastructure sous-jacente de la plateforme Predictive Flowbox. Cela inclus également le<br/>
support de nos clients lors des phases d’appairage ou lors d’incident ou de dysfonctionnement de la plateforme ou de la flowbox en tant que telle.</p>
<p>La solution Predictive Flowbox est composée de deux ensembles :</p>
<ul>
<li>La Predictive Flowbox : périphérique installé sur le réseau d’eau privatif de nos clients - il est composé d’une vanne, d’un débitmètre, d’une sonde de température et d’une carte<br/>
permettant la connexion à notre plateforme, la remontée des métriques et les envois<br/>
d’ordre d’ouverture/fermeture de vannes.</li>
<li>La Plateforme Predictive Flowbox : elle est composée d’une API, d’une WebApp et d’un<br/>
broker MQTT, de bases de données relationnelles et orientée séries temporelles et d’un<br/>
module de machine learning pour les consommations anormales. Cette plateforme<br/>
assure l’ingestion, le stockage, l’analyse et la restitution des données ainsi que la gestion<br/>
des alertes.</li>
</ul>
<p><strong>Missions &amp; Attributions</strong></p>
<p>La personne avec pour role de développeur sénior :</p>
<ul>
<li>Conçoit tous les aspects techniques et fonctionnels du front-end et back-end d’un site<br/>
web ou d’une application (architecture, stockage des données, interface utilisateur,<br/>
sécurité, traitements et processus, …).</li>
<li>Veille au respect des normes et standards en vigueur.</li>
<li>Rédige la documentation technique et forme les utilisateurs.</li>
<li>Effectue la maintenance corrective et évolutive du produit après développement.</li>
<li>Résout les problèmes techniques.</li>
<li>Configure et maintient en bon état de fonctionnement les serveurs d’hébergement et les<br/>
différents composants</li>
<li>Améliore/Optimise de manière continue l’expérience utilisateur.Effectue une veille technologique régulière afin de rester à jour sur les dernières</li>
<li>innovations et identifier les éléments opportuns pour Flovea</li>
<li>Assure le support de nos clients lors des phases d’appairage, de prise en main et<br/>
d’utilisation de la plateforme.</li>
</ul>
<p><strong>Technologies</strong></p>
<ul>
<li>Backend &amp; API : Python 3.13/FastAPI, MQTT, Warp 10 (series temporelles), Postgresql<br/>
14+</li>
<li>WebApp: VueJS (Vue 3), TailwindCSS, Vite</li>
<li>Machine Learning: Python 3.12, Scikit-learn, Darts, KMeans</li>
<li>Ops: Traefik, Ansible, Docker, Docker Compose</li>
<li>Code: Gitlab, Gitlab-CI,</li>
<li>Tests : Pytest, Cypress, Vitest</li>
<li>Lint: Ruff, Eslint</li>
<li>Package Manager : Poetry, Pnpm</li>
<li>Hébergement : OVHCloud (Serveurs dédiés &amp; VMs)</li>
</ul>
<p>La personne va travailler dans un premier temps sur les sujets backend/frontend/ops ; la partie datascience/machine learning se fera dans un second temps ou via l’arrivée d’un profil complémentaire.</p>
<p><strong>Localisation</strong></p>
<p>La personne doit pouvoir se rendre facilement à Saint Paul Lès Dax pour travailler avec<br/>
l’équipe Flowbox sur site. Elle est idéalement localisée en Nouvelle Aquitaine.</p>
<p>Des voyages au Moyen Orient sont possibles (Dubai, Egypte, Jordanie, etc) pour travailler<br/>
avec nos partenaires et clients.</p>
<p><strong>Compétences</strong></p>
<p>La personne doit avoir les compétences suivantes :</p>
<ul>
<li>Concevoir et modéliser des solutions à un besoin exprimé</li>
<li>Savoir travailler en autonomie tout en collaborant avec les salariés / partenaires de<br/>
l’entreprise</li>
<li>Maitrise des méthodologies « agile » (Kanban, revue de code, pair programming, etc)</li>
<li>Capacité à apprendre de nouvelles technologies et de développer de nouveaux usages</li>
<li>Maitrise et mise en œuvre d’architecture applicative et système (Architecture 3 tiers, API,<br/>
etc)</li>
<li>Maitrise de plusieurs langages de programmation frontend et backend et des principes<br/>
de programmation associés</li>
<li>Mise en œuvre des outils et méthodes nécessaires au bon déroulement d’un projet<br/>
(gestion des sources, tests (unitaires, intégration, etc), intégration continue (CI),déploiement continu (CD), etc)</li>
<li>Stockage, traitement et analyse de données (base de données / stockage fichiers,<br/>
traitement batch/streaming, datascience / statistique)</li>
<li>Administration système (Linux) et connaissances réseaux</li>
<li>Connaissance des principes de scalabilité (horizontale et verticale) et être en mesure de<br/>
les déployer</li>
<li>Cybersécurité (notions de base)</li>
</ul>
<p>En plus de ces compétences techniques :</p>
<ul>
<li>La maitrise de l’anglais, tant à l’oral et à l’écrit, doit être courante pour être en mesure de<br/>
travailler avec nos partenaires et clients. La gestion du code se fait en anglais également<br/>
(issues, code, etc)</li>
<li>La personne doit être capable de communiquer avec des personnes non expertes dans<br/>
les domaines IT (simplification, vulgrarisation)</li>
</ul>
<p><strong>Expérience et Salaires</strong></p>
<p>La personne doit disposer d’une expérience solide pour prendre en main le projet et<br/>
travailler en autonomie et en relation direct avec des profils fonctionnels / non techniques.</p>
<p>La personne sera hiérarchiquement rattachée au fondateur de Flovea.</p>
<p>Le salaire est entre 45K€ et 60K€ brut, selon le profil.</p>
<p>Le poste est à pouvoir immédiatement.</p>
<p><strong>Processus de recrutement</strong></p>
<p>Il se fera en deux entretiens :</p>
<ul>
<li>Entretien technique et présentation du projet avec le DSI/CTO de Flovea</li>
<li>Entretien global avec le fondateur de Flovea</li>
</ul>
<p><strong>En savoir plus</strong></p>
<p>Flovea : <a href="https://www.flovea.fr/" rel="noopener nofollow ugc">https://www.flovea.fr/</a></p>
<p>Predictive Flowbox :</p>
<ul>
<li><a href="https://www.predictiveflowbox.com/" rel="noopener nofollow ugc">https://www.predictiveflowbox.com/</a></li>
<li><a href="https://docs.predictiveflowbox.com/" rel="noopener nofollow ugc">https://docs.predictiveflowbox.com/</a></li>
</ul>
<p><strong>Contact</strong></p>
<p>Nicolas Steinmetz - <a href="mailto:ns@flovea.fr">ns@flovea.fr</a> - 0762381324</p>
<p><small>2 messages - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/cdi-dev-senior-fullstack-back-front-ops-nouvelle-aquitaine/2924">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>flovea</name>
        </author>
    </entry>
    <entry>
        <title>Comment nous avons rendu la bibliothèque packaging de Python 3× plus rapide</title>
        <link href="https://iscinumpy.dev/post/packaging-faster/" />
        <id>https://iscinumpy.dev/post/packaging-faster/</id>
        <updated>2026-01-20T15:31:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez comment les mainteneur·se·s de pip et packaging ont optimisé la bibliothèque packaging de Python, utilisée par presque tous les outils de gestion de paquets. Grâce au nouveau profiler statistique de Python 3.15 et aux métadonnées de tous les packages PyPI, iels ont amélioré les performances de lecture des versions et des spécificateurs. Les résultats sont impressionnants : jusqu’à 2x plus rapide pour les Versions, 3x pour les SpecifierSets, et même 5x dans certains cas, tout en gardant le code lisible et simple.</p>
<a href="https://news.humancoders.com/t/python/items/43190-comment-nous-avons-rendu-la-bibliotheque-packaging"><img src="https://iscinumpy.dev/images/avatar.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/43190-comment-nous-avons-rendu-la-bibliotheque-packaging#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/43190-comment-nous-avons-rendu-la-bibliotheque-packaging">Comment nous avons rendu la bibliothèque packaging de Python 3× plus rapide</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>10 ans après, Modoboa est toujours là pour prendre soin de votre serveur de messagerie</title>
        <link href="https://linuxfr.org/users/mirtouf/journaux/10-ans-apres-modoboa-est-toujours-la-pour-prendre-soin-de-votre-serveur-de-messagerie" />
        <id>https://linuxfr.org/users/mirtouf/journaux/10-ans-apres-modoboa-est-toujours-la-pour-prendre-soin-de-votre-serveur-de-messagerie</id>
        <updated>2026-01-19T19:52:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Puisqu'il n'est jamais trop tard pour écrire sur DLFP, voici donc une note de journal concernant <a href="https://modoboa.org/fr/">Modoboa</a> une application écrite en python qui, près de 11 ans après la dernière dépêche à son sujet concernant la version 1.2.0 (nous sommes en version 2.6.5, la version 2.7.0 pointe le bout de son nez) continue de toujours être une solution adaptée pour avoir rapidement un serveur de messagerie fonctionnel et bien doté.<br/>
Le logiciel est toujours développé par @anguyen et je l'en remercie.</p>
<h2 id="toc-rappel-des-fonctionnalités-offertes">Rappel des fonctionnalités offertes</h2>
<h3 id="toc-une-interface-dadministration">Une interface d'administration</h3>
<p>Celle-ci vous permet de gérer les comptes voire de déléguer la gestion d'un domaine, définir des quotas par domaine ou compte, de définir des relais et d'autres choses.<br/>
Il est à noter que l'interface a visuellement bien changé depuis la version 1.2.0.<br/>
<img alt="Réglages" src="https://img.linuxfr.org/img/68747470733a2f2f7265686f73742e646962657269652e636f6d2f506963747572652f4765742f722f343833373632/483762" title="Source : https://rehost.diberie.com/Picture/Get/r/483762"/><br/>
<img alt="Comptes utilisateurs" src="https://img.linuxfr.org/img/68747470733a2f2f7265686f73742e646962657269652e636f6d2f506963747572652f4765742f662f343833373633/483763" title="Source : https://rehost.diberie.com/Picture/Get/f/483763"/><br/>
<img alt="Statistiques" src="https://img.linuxfr.org/img/68747470733a2f2f7265686f73742e646962657269652e636f6d2f506963747572652f4765742f662f343833373634/483764" title="Source : https://rehost.diberie.com/Picture/Get/f/483764"/><br/>
<img alt="Informations du domaine" src="https://img.linuxfr.org/img/68747470733a2f2f7265686f73742e646962657269652e636f6d2f506963747572652f4765742f662f343833373635/483765" title="Source : https://rehost.diberie.com/Picture/Get/f/483765"/><br/>
<img alt="Accueil" src="https://img.linuxfr.org/img/68747470733a2f2f7265686f73742e646962657269652e636f6d2f506963747572652f4765742f662f343833373636/483766" title="Source : https://rehost.diberie.com/Picture/Get/f/483766"/></p>
<p>Cette interface permet une multitude de réglages et notamment pour celles et ceux qui le souhaitent, d'intégrer rspamd ou amavis, de signer ses messages sortants avec dkim, de valider les enregistrements DNS d'un domaine, de s'interfacer avec un annuaire LDAP, etc.</p>
<h3 id="toc-un-webmail">Un webmail</h3>
<p>Pratique pour lire ses messages et y répondre si l'envie nous en prend.</p>
<h3 id="toc-des-filtres-sieve">Des filtres sieve</h3>
<p>Établir des règles sieve pour son tri automatique des messages est clairement le must-have pour s'épargner une tâche rébarbative.</p>
<h3 id="toc-une-gestion-des-calendriers">Une gestion des calendriers</h3>
<p>Le logiciel propose via radicale et un petit module à installer via pip une gestion des calendriers</p>
<h3 id="toc-un-gestion-des-carnets-dadresse">Un gestion des carnets d'adresse</h3>
<p>C'est toujours mieux de pouvoir enregistrer ses contacts n'est-ce pas ?</p>
<h3 id="toc-un-répondeur-automatique">Un répondeur automatique</h3>
<p>Le meilleur outil pour annoncer ses vacances à la Terre entière (ou pas).</p>
<h2 id="toc-quels-changements-depuis-11-ans">Quels changements depuis 11 ans ?</h2>
<p>Plein de choses, je vais donc les citer pêle-mêle:</p>
<ul>
<li>l'ajout d'un service de notification pour prévenir de l'arrivée d'une nouvelle version</li>
<li>une modularisation de Modoboa puis le retour à un fonctionnement quasiment monolithique</li>
<li>l'implémentation d'un contrôle de la robustesse des mots de passe</li>
<li>l'implémentation d'une API REST</li>
<li>la vérification des enregistrements DNS pour un domaine</li>
<li>la fin du support de python 2.x</li>
<li>un démon policy et le support de Redis (Valkey sans doute prochainement)</li>
<li>le support de TOTP (oui !)</li>
<li>une nouvelle interface telle que montrée plus haut</li>
<li>la possibilité de créer et gérer ses clefs DKIM dans Modoboa</li>
<li>la fin programmée des cronjobs (RQ se chargera de tout cela prochainement)</li>
<li>OAUTH2 est supporté (très bien pour intégrer des applications externes)</li>
<li>un service d'auto-configuration pour permettre aux clients lourds de savoir comment se connecter au serveur mail</li>
</ul>
<h2 id="toc-pourquoi-continuer-à-utiliser-modoboa-face-à-lalternative-x-y-ou-z">Pourquoi continuer à utiliser modoboa face à l'alternative X, Y ou Z ?</h2>
<p>Voici une question qui se pose et à laquelle j'ai quelques éléments de réponse. Étant utilisateur depuis plus de 12 ans et ayant même testé la version 0.9.0 sans être convaincu à l'époque, j'ai pu voir le logiciel évoluer avec toujours la possibilité de garder le contrôle de son installation car Modoboa s'installe avec soit un script fourni par les développeurs soit manuellement et à l'heure où certains développeurs ne jurent plus que par docker (pour ne pas le citer), c'est toujours appréciable car cela permet aux personnes comme moi de tuner leur installation plus facilement même si cela implique de bien conserver la trace de ce que l'on fait. En outre, je trouve le logiciel bien pensé et rationnel dans son approche, les fonctionnalités proposées sont souvent celles les plus utiles pour les utilisateurs.<br/>
J'ai pu migrer de la version 1.2.0 à la version 2.6.5 avec assez peu de problèmes et c'est fort appréciable de ne pas devoir repartir de zéro.</p>
<h2 id="toc-les-ressources-utiles">Les ressources utiles</h2>
<p><a href="https://modoboa.readthedocs.io">La documentation</a><br/>
<a href="https://modoboa.org/fr/">Le site web</a><br/>
<a href="https://github.com/modoboa/modoboa/">Le dépôt github du projet</a></p>
<div><a href="https://linuxfr.org/users/mirtouf/journaux/10-ans-apres-modoboa-est-toujours-la-pour-prendre-soin-de-votre-serveur-de-messagerie.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/141996/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/mirtouf/journaux/10-ans-apres-modoboa-est-toujours-la-pour-prendre-soin-de-votre-serveur-de-messagerie#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>mirtouf</name>
        </author>
    </entry>
    <entry>
        <title>Sur Grenoble - Meetup le 27 janvier 2026</title>
        <link href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-27-janvier-2026/2923" />
        <id>https://discuss.afpy.org/t/sur-grenoble-meetup-le-27-janvier-2026/2923</id>
        <updated>2026-01-18T20:33:03Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>On organise à Grenoble mardi 27 janvier 2026 un Meetup Python avec un quiz sur les <strong>nouveautés</strong> et les <strong>avancées marquantes</strong> de l’année 2025. On aura aussi des questions sur le documentaire sur Python sorti en août 2025 : <a href="https://www.youtube.com/watch?v=GfH4QL4VqJ0" rel="noopener nofollow ugc">https://www.youtube.com/watch?v=GfH4QL4VqJ0</a></p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-27-janvier-2026/2923/1" style="font-weight: bold; font-size: 1.1em;">Grand Quiz Python de l'Année 2025</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">January 27, 2026 7:00 PM (Europe/Paris) → January 27, 2026 9:00 PM (Europe/Paris)</td>
</tr>
</tbody></table>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-27-janvier-2026/2923">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Pierre-Loic</name>
        </author>
    </entry>
    <entry>
        <title>Besoin d&#39;aide pour trouver du travail</title>
        <link href="https://discuss.afpy.org/t/besoin-daide-pour-trouver-du-travail/2922" />
        <id>https://discuss.afpy.org/t/besoin-daide-pour-trouver-du-travail/2922</id>
        <updated>2026-01-17T20:15:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Comment trouver un petit travail, je suis programmeur junior en python</p>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/besoin-daide-pour-trouver-du-travail/2922">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Noubi</name>
        </author>
    </entry>
    <entry>
        <title>Linus Torvalds s&#39;essaie au vibe coding : «  C&#39;est mieux que ce que j&#39;aurais fait moi-même »</title>
        <link href="https://linuxfr.org/users/epeios/liens/linus-torvalds-s-essaie-au-vibe-coding-c-est-mieux-que-ce-que-j-aurais-fait-moi-meme" />
        <id>https://linuxfr.org/users/epeios/liens/linus-torvalds-s-essaie-au-vibe-coding-c-est-mieux-que-ce-que-j-aurais-fait-moi-meme</id>
        <updated>2026-01-14T07:06:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.clubic.com/actualite-594901-c-est-mieux-que-ce-que-j-aurais-fait-moi-meme-meme-le-createur-de-linux-code-avec-l-ia.html">https://www.clubic.com/actualite-594901-c-est-mieux-que-ce-que-j-aurais-fait-moi-meme-meme-le-createur-de-linux-code-avec-l-ia.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/141715/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/epeios/liens/linus-torvalds-s-essaie-au-vibe-coding-c-est-mieux-que-ce-que-j-aurais-fait-moi-meme#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Claude SIMON</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 21 janvier</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-21-janvier/2920" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-21-janvier/2920</id>
        <updated>2026-01-13T10:51:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Le prochain meetup sur Lyon a lieu le mercredi 21 janvier à 19h, dans les locaux de GenyMobile (métro Saxe-Gambetta).</p>
<p>Pour ce meetup de rentrée, <a class="mention" href="https://discuss.afpy.org/u/cyrillepontvieux">@CyrillePontvieux</a> nous parlera de la gestion de changelog quand on est plusieurs <img alt=":spiral_notepad:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/spiral_notepad.png?v=15" title=":spiral_notepad:" width="20"/></p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-21-janvier/2920/1" style="font-weight: bold; font-size: 1.1em;">Comment gérer un changelog facilement quand on est plusieurs ?</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">January 21, 2026 7:00 PM (Europe/Paris) → January 21, 2026 10:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://www.meetup.com/fr-fr/python-afpy-lyon/events/312861081/</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-21-janvier/2920">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris - Meetup le 29 janvier</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-le-29-janvier/2919" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-le-29-janvier/2919</id>
        <updated>2026-01-12T22:50:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>On commence l’année avec un nouveau meetup, logés et nourris <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-paris-meetup-le-29-janvier/2919/1" style="font-weight: bold; font-size: 1.1em;">Sur Paris - Meetup le 29 janvier</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">January 29, 2026 7:00 PM (Europe/Paris) → January 29, 2026 10:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">Octopus Energy France - 87 Rue de Richelieu, 75002 Paris</td>
</tr>
</tbody></table>
<p>Lieu : Octopus Energy France - 87 Rue de Richelieu, 75002 Paris<br/>
Lien meetup : <a class="inline-onebox" href="https://www.meetup.com/python-afpy-paris/events/312835003/">Meetup Python, Thu, Jan 29, 2026, 7:00 PM | Meetup</a></p>
<p>On alterne entre moment conviviaux et talk. Il reste un spot pour un court talk si quelqu’un en a l’envie !</p>
<p><small>7 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-29-janvier/2919">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Chadys</name>
        </author>
    </entry>
    <entry>
        <title>sphinxcontrib-run: exécuter du code pendant la génération d&#39;une documentation</title>
        <link href="https://linuxfr.org/users/nlgranger/journaux/sphinxcontrib-run-executer-du-code-pendant-la-generation-d-une-documentation" />
        <id>https://linuxfr.org/users/nlgranger/journaux/sphinxcontrib-run-executer-du-code-pendant-la-generation-d-une-documentation</id>
        <updated>2026-01-06T08:16:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Je commence l'année par une petite contribution open-source pour les documentations de projets python: <a href="https://github.com/sphinx-contrib/sphinxcontrib-run">sphinxcontrib-run</a>.</p>
<p>TLDR; une directive qui permet d'exécuter du code à la volée pendant la génération d'une doc.</p>
<p>Cette extension au générateur de documentation <a href="https://www.sphinx-doc.org/en/master">sphinx</a> concerne la partie des documentations d'API générées automatiquement à partir des commentaires dans le code source, les <a href="https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html">"docstrings"</a>. Les docstrings sont rédigées au format <a href="https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html">reStructuredText</a> qui est un peu plus évolué que markdown et permet d'appeler des directives avec des arguments pour désigner un bloc de code, une référence, un argument de fonctions, etc.</p>
<p>L'extension <code>sphinxcontrib-run</code> ajoute une nouvelle directive <code>.. run::</code> qui prend un morceau de code python en argument et l'exécute immédiatement pendant la construction de la documentation. Plus précisément, un interpréteur python est démarré pour chaque page de documentation traitée par sphinx et, à chaque fois que sphinx insère dans la page un nœud correspondant à la directive <code>.. run::</code>, le code est exécuté dans cet interpréteur.</p>
<p>Au passage, ce que le code écrit sur la sortie standard est inséré dans la documentation.</p>
<p>Voici un exemple pour un module python jouet:</p>
<pre><code class="py"><span class="sd">"""</span>
<span class="sd">.. run::</span>

<span class="sd">    from example import square_text_50</span>

<span class="sd">    lorem = (</span>
<span class="sd">        "Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span>
<span class="sd">        + " Pellentesque faucibus vestibulum est id consequat."</span>
<span class="sd">        + " Cras sed enim sed ex maximus blandit."</span>
<span class="sd">    )</span>
<span class="sd">"""</span>


<span class="k">def</span> <span class="nf">square_text_50</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="sd">"""Wrap text to 40 columns.</span>

<span class="sd">    .. run::</span>

<span class="sd">        print("::")</span>
<span class="sd">        print("")</span>
<span class="sd">        for line in square_text_50(lorem):</span>
<span class="sd">            print("    " + line)</span>
<span class="sd">        print("")</span>
<span class="sd">    """</span>
    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">text</span><span class="p">),</span> <span class="mi">50</span><span class="p">):</span>
        <span class="k">yield</span> <span class="n">text</span><span class="p">[</span><span class="n">i</span> <span class="p">:</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">50</span><span class="p">]</span></code></pre>
<p>Si l'on utilise <a href="https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#directive-automodule"><code>automodule</code></a>, sphinx va traiter toutes les docstrings à la suite dans la même page, et donc sphinxcontrib-run exécutera les morceaux de code dans le même interpréteur.<br/>
La première directive <code>.. run::</code> fait les imports et instancie une variable globale qui pourra servir plusieurs fois.<br/>
La seconde directive intervient dans la documentation de la fonction, elle génère dynamiquement la sortie de la fonction pour faire un exemple.</p>
<p>Dans la documentation, le résultat ressemble à ceci: <img alt="screenshot de la documentation sphinx générée" src="https://img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f737068696e782d636f6e747269622f737068696e78636f6e747269622d72756e2f7261772f6d61696e2f6578616d706c652e6a7067/example.jpg" title="Source : https://github.com/sphinx-contrib/sphinxcontrib-run/raw/main/example.jpg"/></p>
<p>Je vais personnellement utiliser ce projet pour générer automatiquement des figures à insérer dans la doc d'un autre projet, ça m'évitera de les ajouter au dépôt git et d'avoir à les tenir à jour.</p>
<p>Au passage, je note que l'API sphinx pour ajouter des directives est très bien faite et bien documentée.<br/>
Enfin, il faut aussi mentionner un projet similaire au mien: <a href="https://github.com/sphinx-contrib/eval">https://github.com/sphinx-contrib/eval</a></p>
<div><a href="https://linuxfr.org/users/nlgranger/journaux/sphinxcontrib-run-executer-du-code-pendant-la-generation-d-une-documentation.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/141630/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/nlgranger/journaux/sphinxcontrib-run-executer-du-code-pendant-la-generation-d-une-documentation#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>nlgranger</name>
        </author>
    </entry>
    <entry>
        <title>Python Numbers Every Programmer Should Know</title>
        <link href="https://mkennedy.codes/posts/python-numbers-every-programmer-should-know/" />
        <id>https://mkennedy.codes/posts/python-numbers-every-programmer-should-know/</id>
        <updated>2026-01-05T11:12:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Un aide-mémoire contenant des chiffres réels de timing et de consommation mémoire pour guider les décisions critiques en matière de performance en Python. Cette ressource fournit aux développeur·se·s les métriques essentielles pour optimiser leurs applications Python de manière éclairée.</p>
<a href="https://news.humancoders.com/t/python/items/42233-python-numbers-every-programmer-should-know"><img src="https://cdn.mkennedy.codes/posts/python-numbers-every-programmer-should-know/python-numbers-every-programmer-should-know-social.webp"/></a><hr/><a href="https://news.humancoders.com/t/python/items/42233-python-numbers-every-programmer-should-know#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/42233-python-numbers-every-programmer-should-know">Python Numbers Every Programmer Should Know</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Tryton 7.8</title>
        <link href="https://linuxfr.org/news/sortie-de-tryton-7-8" />
        <id>https://linuxfr.org/news/sortie-de-tryton-7-8</id>
        <updated>2026-01-05T09:09:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Le 15 décembre 2025 est sortie avec un petit délai, la version 7.8 de <a href="https://www.tryton.org/">Tryton</a>, un <a href="https://fr.wikipedia.org/wiki/progiciel%20de%20gestion%20int%C3%A9gr%C3%A9" title="Définition Wikipédia">progiciel de gestion intégré</a> modulaire et multiplate-forme.</p>
<p><img alt="Tryton" src="https://img.linuxfr.org/img/68747470733a2f2f646f776e6c6f6164732e747279746f6e2e6f72672f696d616765732f62616e6e65722e737667/banner.svg" title="Source : https://downloads.tryton.org/images/banner.svg"/></p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116786" hreflang="en" title="https://discuss.tryton.org/t/tryton-release-7-8/9015">Annonce 7.8</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/116787" hreflang="fr" title="https://linuxfr.org/news/sortie-de-tryton-7-6">Dépêche sur la sortie 7.6</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/116788" hreflang="fr" title="https://www.tryton.org/demo">Démo</a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/116789" hreflang="fr" title="https://docs.tryton.org/7.8/">Documentation</a></li></ul><div><p>La version 7.8 de Tryton est sortie mi‑décembre 2025 et s’inscrit dans la continuité des branches précédentes, avec une mise à jour axée sur la stabilité, les performances et une série de raffinements fonctionnels dans tous les domaines de gestion. Elle apporte de nombreuses corrections de bogues, améliore la réactivité du serveur et peaufine à la fois l’interface utilisateur, les modules métiers et les outils destinés aux administrateurs et développeurs.</p>
<h2 id="toc-support-peppol">Support PEPPOL</h2>
<p>Suite à l'<a href="https://efacture.belgium.be/fr">obligation pour 2026 en Belgique</a> d’envoyer les factures entre sociétés belges au format électronique via le réseau <a href="https://peppol.org/">PEPPOL</a>, la version 7.8 inclut à temps les modules nécessaires dont un module de connexion au point d’accès gratuit <a href="https://www.peppyrus.be/fr">Peppyrus</a>.<br/>
Quand ces modules sont activés, Tryton envoie automatiquement à partir de 2026 sur le réseau PEPPOL les factures si le client a un numéro de TVA belge (ainsi que la société gérée). Il est aussi possible de forcer l’envoi pour certains clients.<br/>
Les modules sont conçus pour être étendu à d’autres points d’accès futures afin de diversifier l’offre.</p>
<h2 id="toc-interface-et-usage-quotidien">Interface et usage quotidien</h2>
<p>Cette version introduit un système de notifications plus moderne : un menu dédié regroupe les messages, un compteur signale les notifications non lues et des pop‑ups informent l’utilisateur des nouveaux événements sans quitter son écran. Les vues en liste sont plus agréables, avec des boutons d’action visibles en pied de page et des recherches simplifiées, par exemple pour trouver les documents sans entrepôt défini, ce qui rend la navigation au quotidien plus fluide.</p>
<p>Le chat intégré, apparu dans la version précédente comme fonctionnalité émergente, est désormais activée de base sur les documents clés (ventes, achats, factures…) pour centraliser les échanges directement dans le logiciel. Les utilisateurs peuvent s’abonner à un document via une icône de cloche et recevoir des notifications ciblées, renforçant le suivi collaboratif sans dépendre d’outils externes.</p>
<p><img alt="Conversation entre Jim et Dwight sur une vente" src="https://img.linuxfr.org/img/68747470733a2f2f646973637573732d63646e2e747279746f6e2e6f72672f75706c6f6164732f64656661756c742f6f726967696e616c2f32582f372f373662373431353837633166313964376236333464303763326235373732656461386633353862392e706e67/76b741587c1f19d7b634d07c2b5772eda8f358b9.png" title="Source : https://discuss-cdn.tryton.org/uploads/default/original/2X/7/76b741587c1f19d7b634d07c2b5772eda8f358b9.png"/></p>
<h2 id="toc-modules-métiers">Modules métiers</h2>
<p>Sur le plan fonctionnel, la version 7.8 enrichit l’écosystème de modules : gestion des formats de factures électroniques <a href="https://docs.oasis-open.org/ubl/os-UBL-2.4/UBL-2.4.html">UBL</a> et <a href="https://peppol.org/">PEPPOL</a>, gestion de contrats de location (avec facturation progressive), support des agents et de documents (<a href="https://en.wikipedia.org/wiki/Commercial_invoice">facture commerciale</a>) de douane, ainsi que définition plus fine des points d’expédition logistiques par entrepôt.</p>
<p>L’intégration e‑commerce, notamment avec Shopify.com, est nettement améliorée avec la prise en charge des remboursements, des taxes sur les frais de port, des produits de type kit, un choix plus intelligent du transporteur et la synchronisation de la langue du client et des liens d’administration entre boutiques en ligne et Tryton.</p>
<p>Le moteur d’approvisionnement a été ajusté pour mieux gérer les contraintes de délais : si aucun fournisseur ne peut livrer dans le délai idéal, le système choisit automatiquement celui qui offre le délai le plus court, limitant les ruptures tout en restant réaliste. De nouveaux rapports sur la quantité de stock et la <a href="https://fr.wikipedia.org/wiki/rotation%20de%20stock" title="Définition Wikipédia">rotation de stock</a> permettent de suivre plus précisément les niveaux et mouvements, et de prendre de meilleures décisions sur les points de commande et les réassorts.</p>
<p>Les modules de comptabilités supportent maintenant les références de paiement sur les factures et les relevés de compte. Pour l’instance les formats « <a href="https://en.wikipedia.org/wiki/Creditor_Reference">Creditor Reference</a> » et « <a href="https://finances.belgium.be/fr/communication-structuree">Communication structurée</a> » belge sont supportées en standard.</p>
<h2 id="toc-administration-et-développement">Administration et développement</h2>
<p>Côté serveur, Tryton 7.8 réduit la consommation mémoire en envoyant les réponses JSON comme flux et en ne chargeant plus que les modules activés, ce qui profite aux installations avec peu de modules activés (on a mesuré des réductions de la consommation mémoire entre 10% et 20%). Les administrateurs disposent d’un mode console: <em>trytond-console</em> capable d’exécuter maintenant des scripts depuis un fichier et d’un paramètre de rotation des logs basé sur la taille plutôt que sur l’âge, tandis que les développeurs bénéficient du nouveau système de notifications côté serveur, d’optimisations SQL avec l’usage de <code>FILTER</code> et <code>EXISTS</code> et de la possibilité de matérialiser les modèles basés sur une requête SQL (au lieu d’une table).</p>
</div><div><a href="https://linuxfr.org/news/sortie-de-tryton-7-8.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/141483/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/sortie-de-tryton-7-8#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Cédric Krier,Maxime Richez,Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>4 mois de Python de manière intensive: mon retour sur le langage</title>
        <link href="https://mcorbin.fr/posts/2025-12-26-python-langage/" />
        <id>https://mcorbin.fr/posts/2025-12-26-python-langage/</id>
        <updated>2026-01-01T16:06:17Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>En septembre, j’ai changé de poste, et me voilà à manger du Python toute la journée. Je décrirai dans cet article mon expérience avec le langage.</p>
<p>Background
J’ai appris à programmer comme beaucoup en lisant des tutoriels sur internet il y a presque 20 ans, avec HTML/PHP et C.
Pendant mes études, j’ai eu l’occasion de toucher à plein de langages: Java, C, PHP (que j’aimais beaucoup car je pouvais facilement faire un site web sympa en codant comme un cochon), Ocaml, ou des choses un peu plus obscures comme VHDL (c’était ultra fun et intéressant) et Cobol.</p>
<p>Durant ma carrière, j’ai alterné entre des rôles de dev/lead dev et de SRE (où je codais toujours énormément: infrastructure API-first, self-service, platform engineering, tooling…​). J’ai notamment travaillé 6 ans avec Golang, 4 ans avec Clojure, j’ai été payé pour faire du Java et du Typescript, et je continue d’explorer d’autres langages sur mon temps libre. Bien sûr, nous sommes entre personnes civilisées, donc je ne mentionnerai pas shell/bash ici.</p>
<p>Comme tout bon sysadmin/SRE qui se respecte, j’ai fait du Python, mais à l’arrache. D’ailleurs, le second article de ce blog (2016!) explique comment développer un plugin Ansible (donc en Python) pour générer des logs structurés de l’outil et en dériver des métriques.
J’avais aussi de temps en temps l’occasion de contribuer à des codebases Python, et je n’aimais pas ça, notamment à cause de la gestion des dépendances qui était en dessous de tout.</p>
<p>En septembre 2025, après 3 ans et demi à bosser comme SRE, j’ai décidé de revenir sur un rôle plus proche du produit et du développement, toujours au même endroit mais dans une nouvelle équipe. Vu que c’est un rôle avec également une grosse composante AI, on est parti sur Python.</p>
<p>Quatre mois plus tard et avec un premier produit en prod, j’ai envie de faire un REX sur Python vu que j’ai énormément appris sur le langage pendant cette période.</p>
<a href="https://news.humancoders.com/t/python/items/42136-4-mois-de-python-de-maniere-intensive-mon-retour-s"><img src="https://www.mcorbin.fr/img/singe.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/42136-4-mois-de-python-de-maniere-intensive-mon-retour-s#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/42136-4-mois-de-python-de-maniere-intensive-mon-retour-s">4 mois de Python de manière intensive: mon retour sur le langage</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Debutante Python</title>
        <link href="https://discuss.afpy.org/t/debutante-python/2910" />
        <id>https://discuss.afpy.org/t/debutante-python/2910</id>
        <updated>2025-12-29T19:12:24Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour. <img alt=":waving_hand:t2:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/waving_hand/2.png?v=15" title=":waving_hand:t2:" width="20"/></p>
<p>Je suis une lycéenne et encore une débutante en programmation. <img alt=":smiling_face_with_tear:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiling_face_with_tear.png?v=15" title=":smiling_face_with_tear:" width="20"/></p>
<p>Cette année, dans le cadre d’un projet scolaire, nous sommes amenés à créer une application d’autogestion pour aider les personnes qui trouvent des difficultés à gérer leur temps et à s’autogérer..</p>
<p>Et en tant que débutante j’ai besoin de réponses à certaines questions sur les fonctionnalités à intégrer dans l’application ainsi que sur les techniques de programmation Python.</p>
<p>Merci de m’accorder un peu de votre temps ce sera vraiment gentil. Merciii. <img alt=":folded_hands:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/folded_hands.png?v=15" title=":folded_hands:" width="20"/></p>
<p><small>15 messages - 7 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/debutante-python/2910">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Manar</name>
        </author>
    </entry>
    <entry>
        <title>Quels sont les principaux langages derrière les GNOME Core apps ? Pas Python : moins de 7% du code !</title>
        <link href="https://linuxfr.org/users/antistress/liens/quels-sont-les-principaux-langages-derriere-les-gnome-core-apps-pas-python-moins-de-7-du-code" />
        <id>https://linuxfr.org/users/antistress/liens/quels-sont-les-principaux-langages-derriere-les-gnome-core-apps-pas-python-moins-de-7-du-code</id>
        <updated>2025-12-28T00:49:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://blogs.gnome.org/sophieh/2025/12/27/gnome-in-2025-some-numbers/">https://blogs.gnome.org/sophieh/2025/12/27/gnome-in-2025-some-numbers/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/141525/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/antistress/liens/quels-sont-les-principaux-langages-derriere-les-gnome-core-apps-pas-python-moins-de-7-du-code#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>antistress</name>
        </author>
    </entry>
    <entry>
        <title>DevOps Confirmé / Bruxelles / CDD 2 ans / Ministère Économie et des Finances (A+)</title>
        <link href="https://discuss.afpy.org/t/devops-confirme-bruxelles-cdd-2-ans-ministere-economie-et-des-finances-a/2908" />
        <id>https://discuss.afpy.org/t/devops-confirme-bruxelles-cdd-2-ans-ministere-economie-et-des-finances-a/2908</id>
        <updated>2025-12-22T15:34:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon" height="500" src="https://passerelles.economie.gouv.fr/DynamicContent/Images/Picto/favicon.ico" width="514"/>
<a href="https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-devops-confirme-e-peren-aoce-1-h-f_26925.aspx" rel="noopener nofollow ugc" target="_blank">passerelles.economie.gouv.fr</a>
</header>
<article class="onebox-body">
<h3><a href="https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-devops-confirme-e-peren-aoce-1-h-f_26925.aspx" rel="noopener nofollow ugc" target="_blank">MINISTERE DE L'ECONOMIE ET DES FINANCES - DevOps confirmé(e) - PEReN -AOCE -1...</a></h3>
<p>Offre d'emploi Direction générale des entreprises (DGE) de 'DevOps confirmé(e) - PEReN -AOCE -1 H/F'. Lieu : BRUXELLES. Date : 18/12/2025. Ref : 2025-26925.</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>Emploi ouvert aux contractuels (<a href="https://www.fonction-publique.gouv.fr/files/files/ArchivePortailFP/www.fonction-publique.gouv.fr/grilles-de-carrieres-categorie-a-et-divers-emplois-type-de-ladministration.html" rel="noopener nofollow ugc">Catégorie A+</a>), temps plein, télétravail (2j/semaine), déplacement mensuel à Paris. Les candidatures se font obligatoirement depuis le site <a href="https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-devops-confirme-e-peren-aoce-1-h-f_26925.aspx" rel="noopener nofollow ugc">passerelles.economie.gouv.fr</a>.</p>
<p><strong>Descriptif de l’employeur</strong></p>
<p>Le service à compétence nationale (SCN) dénommé <a href="https://www.peren.gouv.fr/" rel="noopener nofollow ugc">« Pôle d’Expertise de la Régulation Numérique » (PEReN)</a>, a pour mission d’apporter son expertise et son assistance techniques aux services de l’État et autorités administratives intervenant dans la régulation des plateformes numériques. Il est placé sous l’autorité des ministres chargés de l’économie, de la communication et du numérique et rattaché au <a href="https://www.entreprises.gouv.fr/" rel="noopener nofollow ugc">Directeur Général des Entreprises (DGE)</a> pour sa gestion administrative et financière.<br/>
Le PEReN, constitué actuellement de <a href="https://www.peren.gouv.fr/equipe/" rel="noopener nofollow ugc">30 personnes</a>, réunit les expertises humaines et ressources technologiques principalement dans les domaines du traitement des données, de la data science et de l’analyse algorithmique. Il fournit son savoir-faire technique aux services de l’État et autorités administratives qui le sollicitent (par exemple, Autorité de la concurrence, ARCOM, CNIL, ARCEP, ou directions ministérielles telles que la DGE, la DGCCRF, la DGT ou la DGMIC) en vue d’accéder à une compréhension approfondie des écosystèmes d’information exploités par les grands acteurs du numérique.<br/>
Le PEReN est également un centre d’expertise mutualisé entre les différents services de l’État qui conduit une réflexion sur la régulation des plateformes numériques et les outils de cette régulation, dans une approche à la pointe des avancées scientifiques.<br/>
Il a également vocation à animer un réseau de recherche dédié à la régulation des grandes plateformes numériques, et peut être amené à réaliser à son initiative des travaux de recherche académique liés aux différentes thématiques.</p>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12512-description-du-profil-recherch-1" name="p-12512-description-du-profil-recherch-1"></a>Description du profil recherché</h3>
<p>Vous disposez d’une expérience professionnelle d’au moins 3 ans en tant que DevOps. Vous savez par ailleurs mobiliser vos savoirs en autonomie :</p>
<ul>
<li>Bonne connaissance des technologies de conteneurisation et d’orchestration (de type Kubernetes) ;</li>
<li>Des connaissances avancées en administration des systèmes sous Linux ;</li>
<li>Utilisation de Git ;</li>
<li>Maîtrise des processus de développements (revue de code, système de tickets, forge logicielle, CI/CD) ;</li>
<li>Expérience de travail avec au moins un fournisseur de Cloud ;</li>
<li>Connaissance de l’écosystème Python 3 (Python 3.13+, bibliothèques usuelles d’analyse de données, écriture de tests unitaires) et des bonnes pratiques de développement associées.</li>
</ul>
<p>Compte tenu des interactions fréquentes avec le personnel de la Commission Européenne, une bonne maîtrise de l’anglais est indispensable.</p>
<ul>
<li>Les expériences et connaissances suivantes seront considérées comme des atouts sans pour autant être strictement requises dans le contexte de cette fiche de poste :</li>
<li>Expérience dans un contexte fonction publique ou de projet européen ;</li>
<li>Expérience en évaluation de systèmes d’IA, notamment d’utilisation du <a href="https://inspect.aisi.org.uk/" rel="noopener nofollow ugc">framework Inspect</a>. et/ou d’évaluation d’agents dans une <em>sandbox</em>.</li>
</ul>
<h3><a class="anchor" href="https://discuss.afpy.org#p-12512-description-du-poste-2" name="p-12512-description-du-poste-2"></a>Description du poste</h3>
<p>Le <a href="https://www.entreprises.gouv.fr/decryptages-de-nos-experts/le-reglement-europeen-sur-lintelligence-artificielle-publics-concernes" rel="noopener nofollow ugc">Règlement sur l’Intelligence Artificielle (RIA)</a> est une législation européenne, entrée en application le 1er août 2024, qui impose aux fournisseurs et déployeurs de modèles et systèmes d’IA, en particulier les fournisseurs de modèles d’IA à usage général (GPAI), des obligations, notamment en matière de transparence et de sécurité. Son article 92 autorise le <a href="https://digital-strategy.ec.europa.eu/fr/policies/ai-office" rel="noopener nofollow ugc">Bureau de l’IA de la Commission Européenne</a> à effectuer des évaluations des GPAI afin de s’assurer de leur conformité avec le RIA.</p>
<p>Dans ce cadre, le Bureau de l’IA va confier le développement d’une interface d’évaluation de modèles d’IA agentiques ainsi que le déploiement sur son infrastructure de cette interface à un organisme spécialisé. Le PEReN s’est positionné pour se voir confier la réalisation de ce projet, en s’associant à un partenaire institutionnel.</p>
<p>Intégré(e) au sein d’une équipe dédiée de six personnes ayant une expertise dans le domaine, vous mettez en œuvre et êtes responsable du développement d’un plugin Inspect et du déploiement et de la maintenance de la solution développée. Cette équipe est composée de deux développeur(euse)s, d’un(e) autre devOps, d’un(e) ingénieur(e) évaluation de l’IA et un(e) chef(fe) de projet. Vous échangerez également de manière régulière avec l’équipe d’administrateurs systèmes du PEReN en charge de la gestion de notre infrastructure, notamment le DevOps et le responsable des systèmes d’information (RSSI). Vous serez également intégré à l’équipe du PEReN qui dispose de compétences et ressources mobilisables sur ces sujets, et accompagné par un porteur de projet expérimenté.</p>
<p>Vous serez amené(e) à :</p>
<ul>
<li>Mettre en place, en lien avec le deuxième DevOps, une infrastructure de test répliquant l’infrastructure de la Commission Européenne.</li>
<li>Déployer des évaluations à l’échelle sur les infrastructures Cloud de la Commission Européenne en utilisant le code développé au cours du projet, en appui avec le personnel de la Commission ;</li>
<li>En particulier, pour des benchmarks à déployer dans des environnements sandbox conteneurisés, à écrire des Dockerfile si besoin, à identifier des charts Helm pertinents et à écrire des fichiers values ;</li>
<li>Développer un plugin pour déployer des évaluations avec Inspect sur des environnements sandbox de type VM afin de traiter les évaluations à haut risque nécessitant une forte isolation ;</li>
<li>Archiver des jobs d’évaluation pour mise à disposition de la Commission Européenne ;</li>
</ul>
<p>Davantage de détails sur le contexte du projet sont disponibles à l’<a href="https://ec.europa.eu/info/funding-tenders/opportunities/portal/screen/opportunities/tender-details/docs/76f9edf2-d9e2-4db2-931e-a72c5ab356d2-CN/EN_TENDER_SPECIFICATIONS_EC-CNECT-2025-OP-0032_AI%20Safety%20Tools_V1.pdf" rel="noopener nofollow ugc">adresse suivante</a>.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/devops-confirme-bruxelles-cdd-2-ans-ministere-economie-et-des-finances-a/2908">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>plp</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;automne 2025</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2025" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2025</id>
        <updated>2025-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
<li><a href="https://libretic.fr/">Libretic</a> organise une levée de fonds pour financer la campagne de <a href="https://www.demailnagement.net/">DéMAILnagement</a> initiée par le collectif des <a href="https://www.chatons.org/">Chatons</a>. L'objectif de cette campagne est de fournir des solutions de contournement des géants du web.</li>
</ul>
<h2><a href="https://github.com/jnavila/git-manpages-l10n">git-manpages-l10n</a></h2>
<p><em>Traductions de la documentation de GIT</em></p>
<ul>
<li>Correction de <a href="https://github.com/jnavila/git-manpages-l10n/pull/154">traductions manquantes concernant des noms de branche</a> et de <a href="https://github.com/jnavila/git-manpages-l10n/pull/152">coquilles dans des traductions de noms de branche</a></li>
<li>Ajout de traductions manquantes pour git-switch : <a href="https://github.com/jnavila/git-manpages-l10n/pull/154">1</a> et <a href="https://github.com/jnavila/git-manpages-l10n/pull/162">2</a></li>
</ul>
<h2><a href="https://github.com/authlib/authlib">authlib</a></h2>
<p><em>La bibliothèque Python ultime pour construire des clients et serveurs OAuth et OpenID Connect. Inclut JWS, JWE, JWK, JWA, JWT.</em></p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/843">La métadonnée client <code>id_token_signed_response_alg</code> prend le pas sur <code>get_jwt_config</code> du serveur</a></li>
<li><a href="https://github.com/authlib/authlib/pull/844"><code>get_jwt_config</code> prend un paramètre <code>client</code></a></li>
</ul>
<h2><a href="https://github.com/joke2k/faker">faker</a></h2>
<p><em>Faker est un paquet Python qui génère des données fictives.</em></p>
<ul>
<li><a href="https://github.com/joke2k/faker/pull/2279">Implémentation d'UniqueProxy localisé</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/flask-wtf">flask-wtf</a></h2>
<p><em>Intégration simple de Flask et WTForms.</em></p>
<ul>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/648">Support de Python 3.14</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/649">Migration du projet vers uv</a></li>
</ul>
<h2><a href="https://github.com/authlib/joserfc">joserfc</a></h2>
<p><em>Implémentations des RFC JOSE en Python</em></p>
<ul>
<li><a href="https://github.com/authlib/joserfc/pull/79">Le paramètre <code>names</code> de <code>filter_algorithms</code> vaut par défaut tous les algorithmes</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/80"><code>check_key</code> vérifie la compatibilité de la courbe avec EdDSA</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/81">Support des objets KeySet pour <code>filter_algorithms</code> et <code>guess_alg</code></a></li>
<li><a href="https://github.com/authlib/joserfc/pull/83">Le paramètre <code>algorithm</code> de <code>pick_random_key</code> est optionnel</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/84">Ajout de mypy à pre-commit</a></li>
</ul>
<h2><a href="https://github.com/felix-martel/pydanclick">pydanclick</a></h2>
<p><em>Ajoute des options click à partir d'un modèle Pydantic</em></p>
<ul>
<li><a href="https://github.com/felix-martel/pydanclick/pull/55">Résolution des alias de validation</a></li>
</ul>
<h2><a href="https://github.com/jag-k/pydantic-settings-export">pydantic-settings-export</a></h2>
<p><em>Exportez facilement vos paramètres Pydantic vers de la documentation</em></p>
<ul>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/46">Fin du support de Python 3.9</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/47">Générateur Toml</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/49">Expansion des paramètres imbriqués union/optionnels en variables d'environnement</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/50">Mise en place des workflows GHA</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/51">Export des instances de paramètres</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/53">Tests unitaires pour les générateurs</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Construisez des requêtes SCIM et analysez des réponses SCIM de manière pythonique</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/33">Ajout du support de Python 3.14 et fin du support de Python 3.9</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/112">Ajout du support de Python 3.14 et fin du support de Python 3.9</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>Vérificateur de conformité aux RFC SCIM pour serveurs</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/43">Ajout du support de Python 3.14</a></li>
</ul>
<h2><a href="https://github.com/bebleo/smtpdfix">smtpdfix</a></h2>
<p><em>Un serveur SMTP utilisable comme fixture pytest, implémentant le chiffrement et l'authentification.</em></p>
<ul>
<li><a href="https://github.com/bebleo/smtpdfix/pull/448">Accélération des connexions SSL</a></li>
</ul>
<h2><a href="https://github.com/tushuhei/sphinxcontrib-screenshot">sphinxcontrib-screenshot</a></h2>
<ul>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/76">Implémentation du paramètre <code>:status-code:</code></a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/78">Mode sombre automatique</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/80">Support de Python 3.14</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/88">Personnalisation du timeout</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Logiciel léger de gestion d'identité et d'autorisation</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/297">Configuration d'hypercorn via variables d'environnement et options CLI</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/298">Les jetons d'enregistrement de client OIDC sont des JWT</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/301">Documentation des recommandations ANSSI</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/302">Tests unitaires PostgreSQL et corrections de bugs diverses</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/303">Implémentation du support OIDC du paramètre <code>ui_locales</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/304">Bouton de visibilité du mot de passe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/305">Correction de l'implémentation de ProxyFix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/306">Implémentation du multi-compte</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/307">Implémentation du claim AMR</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/308">Implémentation du support WebAuthn/Fido2</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/309">Support des sessions côté serveur</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/310">Implémentation de la protection par Captcha</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/311">Affichage de tous les messages flash sous la section d'en-tête</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/312">Inclusion des données Babel manquantes dans le binaire pyinstaller</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/313">Support de Python 3.14</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/314">Suite de tests d'intégration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/315">La signature du jeton ID sélectionne une clé compatible avec <code>id_token_signed_response_alg</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/317">Les claims d'algorithmes de signature OIDC discovery sont calculés dynamiquement à partir des clés serveur</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Autumn 2025 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2025" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2025</id>
        <updated>2025-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
<li><a href="https://libretic.fr/">Libretic</a> is organizing a fundraising campaign to finance the <a href="https://www.demailnagement.net/">DéMAILnagement</a> campaign initiated by the <a href="https://www.chatons.org/">Chatons</a> collective. The goal of this campaign is to provide workarounds for the web giants.</li>
</ul>
<h2><a href="https://github.com/jnavila/git-manpages-l10n">git-manpages-l10n</a></h2>
<p><em>GIT Documentation Translations</em></p>
<ul>
<li>Fix <a href="https://github.com/jnavila/git-manpages-l10n/pull/154">missing branch name translations</a> and <a href="https://github.com/jnavila/git-manpages-l10n/pull/152">spellcheck branch name translations</a></li>
<li>Add missing translations for git-switch: <a href="https://github.com/jnavila/git-manpages-l10n/pull/154">1</a> et <a href="https://github.com/jnavila/git-manpages-l10n/pull/162">2</a></li>
</ul>
<h2><a href="https://github.com/authlib/authlib">authlib</a></h2>
<p><em>The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS, JWE, JWK, JWA, JWT included.</em></p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/843">Client <code>id_token_signed_response_alg</code> metadata takes precedence over server <code>get_jwt_config</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/844"><code>get_jwt_config</code> takes a <code>client</code> parameter.</a></li>
</ul>
<h2><a href="https://github.com/joke2k/faker">faker</a></h2>
<p><em>Faker is a Python package that generates fake data for you.</em></p>
<ul>
<li><a href="https://github.com/joke2k/faker/pull/2279">Implement localized UniqueProxy</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/flask-wtf">flask-wtf</a></h2>
<p><em>Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.</em></p>
<ul>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/648">Support for Python 3.14</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/649">Migrate the project to uv</a></li>
</ul>
<h2><a href="https://github.com/authlib/joserfc">joserfc</a></h2>
<p><em>Implementations of JOSE RFCs in Python</em></p>
<ul>
<li><a href="https://github.com/authlib/joserfc/pull/79"><code>filter_algorithms</code> names parameter default to all algs</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/80">check_key checks the curve compatibility with EdDSA</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/81">KeySet objects support for <code>filter_algorithms</code> and <code>guess_alg</code></a></li>
<li><a href="https://github.com/authlib/joserfc/pull/83"><code>pick_random_key</code> <code>algorithm</code> parameter is optional</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/84">add mypy to pre-commit</a></li>
</ul>
<h2><a href="https://github.com/felix-martel/pydanclick">pydanclick</a></h2>
<p><em>Add click options from a Pydantic model</em></p>
<ul>
<li><a href="https://github.com/felix-martel/pydanclick/pull/55">Resolve validation aliases</a></li>
</ul>
<h2><a href="https://github.com/jag-k/pydantic-settings-export">pydantic-settings-export</a></h2>
<p><em>Export your Pydantic settings to documentation with ease!</em></p>
<ul>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/46">Stop support for Python 3.9</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/47">Toml generator</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/49">Expand union/optional nested settings to environment variables</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/50">Setup GHA workflows</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/51">Export settings instances</a></li>
<li><a href="https://github.com/jag-k/pydantic-settings-export/pull/53">Unit tests for the generators</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Pythonically build SCIM requests and parse SCIM responses</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/33">Add support for Python 3.14 and remove support for Python 3.9</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/112">Add support for Python 3.14 and remove support for Python 3.9</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>SCIM RFCs server compliance checker</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/43">Add support for Python 3.14</a></li>
</ul>
<h2><a href="https://github.com/bebleo/smtpdfix">smtpdfix</a></h2>
<p><em>A SMTP server for use as a pytest fixture that implements encryption and authentication.</em></p>
<ul>
<li><a href="https://github.com/bebleo/smtpdfix/pull/448">Speed-up ssl connections</a></li>
</ul>
<h2><a href="https://github.com/tushuhei/sphinxcontrib-screenshot">sphinxcontrib-screenshot</a></h2>
<ul>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/76">Implement :status-code: parameter</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/78">Automatic dark mode</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/80">Python 3.14 support</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/pull/88">Timeout customization</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/297">Configure hypercorn with environment vars and CLI options</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/298">OIDC client registration tokens are JWTs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/301">Document ANSSI recommandations</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/302">PostgreSQL unittest and various bugfixes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/303">Implement OIDC ui_locales support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/304">Password visibility toggle button</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/305">Fix ProxyFix implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/306">Implement multi account</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/307">Implement AMR claim</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/308">Implement WebAuthn/Fido2 support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/309">Server-side sessions support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/310">Implement captcha protection</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/311">Display all the flash messages under the header section</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/312">Include missing Babel data in the pyinstaller binary</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/313">Python 3.14 support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/314">Integration test suite</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/315">ID token signing selects a key compatible with id_token_signed_response_alg</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/317">OIDC discovery signing algorithm claims are dynamically computed from server keys</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Rapport de transparence de la PyConFR 2025</title>
        <link href="https://discuss.afpy.org/t/rapport-de-transparence-de-la-pyconfr-2025/2905" />
        <id>https://discuss.afpy.org/t/rapport-de-transparence-de-la-pyconfr-2025/2905</id>
        <updated>2025-12-17T15:12:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>PyCon France (PyConFR) est une conférence qui a lieu chaque année (sauf circonstances exceptionnelles) en France. Cette année, elle a eu lieu du <a href="https://www.pycon.fr/2025" rel="noopener nofollow ugc">30 octobre au 2 novembre à Lyon</a>, rassemblant des personnes de la communauté Python. Les participantes et participants à la conférence sont tenues de respecter ​le <a href="https://www.afpy.org/docs/charte" rel="noopener nofollow ugc">Code de Conduite</a> de l’Association Francophone Python, l’association qui organise l’événement.</p>
<p>Le but de ce document est d’améliorer l’accueil et la sécurité des participantes et participants ainsi que de donner aux organisateurs et organisatrices des indicateurs sur le comportement de la communauté. En effet, pour pouvoir entendre, il faut pouvoir écouter. C’est maintenant devenu une pratique courante, pour les organisations ayant un Code de Conduite, de publier un rapport de transparence suite à la tenue d’une conférence. C’est le but de ce document.</p>
<p><a href="https://git.afpy.org/AFPy/gestion/src/branch/master/compte_rendus_diversite/2025.pdf" rel="noopener nofollow ugc">Télécharger le rapport en PDF (FR/EN)</a></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/rapport-de-transparence-de-la-pyconfr-2025/2905">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>ReiNula</name>
        </author>
    </entry>
    <entry>
        <title>À propos de la catégorie DjangoCong</title>
        <link href="https://discuss.afpy.org/t/a-propos-de-la-categorie-djangocong/2901" />
        <id>https://discuss.afpy.org/t/a-propos-de-la-categorie-djangocong/2901</id>
        <updated>2025-12-17T07:25:19Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>(Remplacez ce paragraphe par une courte description de votre nouvelle catégorie. Cette information apparaîtra dans la zone de sélection de la catégorie, veillez donc à saisir moins de 200 caractères.)</p>
<p>Utilisez les paragraphes suivants pour une plus longue description ou pour établir des règles :</p>
<ul>
<li>
<p>À quoi sert cette catégorie ? Pourquoi les utilisateurs choisiraient-ils cette catégorie pour leur discussion ?</p>
</li>
<li>
<p>En quoi est-elle différente des autres catégories existantes ?</p>
</li>
<li>
<p>Quels sont les sujets qui devraient figurer dans cette catégorie ?</p>
</li>
<li>
<p>Avons-nous besoin de cette catégorie ? Devrions-nous fusionner celle-ci avec une autre catégorie ?</p>
</li>
</ul>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/a-propos-de-la-categorie-djangocong/2901">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>debnet</name>
        </author>
    </entry>
    <entry>
        <title>Traduction de &#34;subscript&#34; et &#34;subscriptable&#34; ?</title>
        <link href="https://discuss.afpy.org/t/traduction-de-subscript-et-subscriptable/2900" />
        <id>https://discuss.afpy.org/t/traduction-de-subscript-et-subscriptable/2900</id>
        <updated>2025-12-16T15:07:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Comment traduiriez-vous “subscript” et “subscriptable” ?</p>
<p><small>6 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/traduction-de-subscript-et-subscriptable/2900">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>DorianTurba</name>
        </author>
    </entry>
    <entry>
        <title>Sur Grenoble - Meetup le 16 décembre</title>
        <link href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-16-decembre/2896" />
        <id>https://discuss.afpy.org/t/sur-grenoble-meetup-le-16-decembre/2896</id>
        <updated>2025-12-14T17:43:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>On organise à Grenoble mardi 16 décembre 2025 un Meetup Python avec des présentations courtes (lightning talks)</p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-16-decembre/2896/1" style="font-weight: bold; font-size: 1.1em;">Lightning talks</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">December 16, 2025 7:00 PM (Europe/Paris) → December 16, 2025 9:00 PM (Europe/Paris)</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-16-decembre/2896">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Pierre-Loic</name>
        </author>
    </entry>
    <entry>
        <title>Je lis du code généré</title>
        <link href="https://linuxfr.org/users/ryan/journaux/je-lis-du-code-genere" />
        <id>https://linuxfr.org/users/ryan/journaux/je-lis-du-code-genere</id>
        <updated>2025-12-12T14:21:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut les moules</p>
<p>J'écris souvent ; rarement ici.</p>
<p>J'ai depuis quelques semaines le bonheur de suivre quelques devs débutants, ou aspirants devs. Je lis donc du code généré, ma joie est grande. Je profite de ce vendredi pour partager avec vous mes impressions. L'incubateur d'excellence qu'est DLFP aura, si je suis chanceux, d'autres retours d'expérience à partager.</p>
<h2 id="toc-cest-propre">C'est propre.</h2>
<p>Plus propre que du code humain. Trop propre. Ce que tu gagnes en lisibilité, tu le perds en concision, en expressivité et en sens. Au fond, rien ne change. Le code décrit le comment, alors que ce qui m'intéresse reste le pourquoi.</p>
<p>Il n'y a évidemment pas de tests. Rien à voir avec la génération. De toute façon il faudra tout reprendre pour intégrer un vrai dispositif de tests, condition nécessaire pour que je fasse confiance au programme.</p>
<p>Le code généré se repère immédiatement: fonctions bien nommées, formatage impeccable, docstrings qui brillent, noms de variables trop précis, aucune variable a, b, x, tmp, out, typage strict des entrées et sorties etc. Un niveau de détail souvent trop fin, l'inverse d'un code en cours d'écriture.</p>
<h2 id="toc-cette-forme-parfaite-est-trompeuse">Cette forme parfaite est trompeuse.</h2>
<p>Tu crois que le code fait le travail. Peut-être au niveau micro, les fonctions sont surement correctes. Au niveau macro, macache. Alors comment être sûr que ce code fait ce qu'il annonce ? En découplant les fonctions et en le disséquant pièce par pièce.</p>
<p>C'est certes plus agréable à lire, mais tu perds un indicateur essentiel. La maturité disparaît. La forme est standardisée. Il n'y a plus de code smell, plus de style, plus de rugosité. Comment juger du fond uniquement à la lecture ?</p>
<p>Certains codes écrits n'importe comment se repèrent au premier coup d'œil. C'est une alerte. Pas de structure, fonctions fleuves de 100 lignes, pas de séparation fond/forme. Un brouillon intégral. Et les brouillons doivent être réécrits.</p>
<p>Le même code, rédigé proprement, structuré, soigné, fera tout aussi n'importe quoi donnera l'impression que c'est pensé. L'impression d'une intention, de la crasse propre.</p>
<h2 id="toc-de-la-crasse-propre">De la crasse propre ?</h2>
<p>Oui mais c'est trolldi, alors je vous en prie.</p>
<p>Avec le code généré, tu perds la possibilité de juger sur l'apparence. Plus de style, plus de subtilités, plus de petites variables piégées. Si tout est bien nommé, comment repérer ce qui compte vraiment ?</p>
<p>Avec ce code aseptisé, je vais peut-être perdre du temps.<br/>
Ou pas.</p>
<p>(publié <a href="https://algonaute.fr/fr/je-lis-du-code-genere.html">ici</a> aussi)</p>
<div><a href="https://linuxfr.org/users/ryan/journaux/je-lis-du-code-genere.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/141343/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/ryan/journaux/je-lis-du-code-genere#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Thomas</name>
        </author>
    </entry>
    <entry>
        <title>Problème exécution fichier IDLE</title>
        <link href="https://discuss.afpy.org/t/probleme-execution-fichier-idle/2894" />
        <id>https://discuss.afpy.org/t/probleme-execution-fichier-idle/2894</id>
        <updated>2025-12-09T22:34:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonsoir tout le monde !</p>
<p>Débutant sur python je viens de commencer à prendre en main un éditeur de code, en l’occurrence IDLE (avant ça je codais via le terminal lol) et je rencontre un problème depuis quelque temps quand j’enregistre (en .py) mon code et que j’ouvre le fichier pour qu’il s’exécute celui-ci s’ouvre sur une fenêtre puis disparaît instantanément.                                      Si quelqu’un pourrait m’aider merci d’avance <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<p><small>4 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-execution-fichier-idle/2894">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Libtak</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 18 décembre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-18-decembre/2893" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-18-decembre/2893</id>
        <updated>2025-12-09T08:31:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Meetup de fin d’année le jeudi 18 décembre, dans les locaux de <a href="https://www.lowit.fr/">Lowit</a> (métro Part-Dieu) !</p>
<p>Comme l’an dernier, on vous propose un format Lightning Talks <img alt=":christmas_tree:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/christmas_tree.png?v=15" title=":christmas_tree:" width="20"/></p>
<p>Si vous souhaitez parler de quelque chose, d’une bibliothèque, d’un outil, d’un projet… N’hésitez pas à me contacter pour que je rajoute sur la liste des sujets <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<p>(dans la limite des slots disponibles)</p>
<table border="0" cellpadding="0" cellspacing="0" style="border: 1px solid #dedede; margin-bottom: 10px; width: 100%;">
<tbody><tr>
<td style="padding: 12px;">
<a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-18-decembre/2893/1" style="font-weight: bold; font-size: 1.1em;">Lightning Talks de Noël 🎄</a>
</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">December 18, 2025 7:00 PM (Europe/Paris) → December 18, 2025 10:00 PM (Europe/Paris)</td>
</tr>
<tr>
<td style="padding: 0 12px 12px; color: #666;">https://www.meetup.com/fr-fr/python-afpy-lyon/events/312350756/</td>
</tr>
</tbody></table>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-18-decembre/2893">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Skull King : priorités entre les cartes sous forme de graphes</title>
        <link href="https://ascendances.wordpress.com/2025/12/08/skull-king-priorites-entre-les-cartes-sous-forme-de-graphes/" />
        <id>https://ascendances.wordpress.com/2025/12/08/skull-king-priorites-entre-les-cartes-sous-forme-de-graphes/</id>
        <updated>2025-12-08T21:31:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Skull King est un jeu de plis sur un thème de pirates, existant depuis plusieurs années en diverses versions.</p>
<h3 class="wp-block-heading">Présentation rapide du jeu</h3>
<p>Plusieurs cartes et effets ont été ajoutés au fil des éditions. Par exemple, une version éditée par Schmidt contient 66 cartes (cartes de couleurs allant de 1 à 13, fuites, pirates, sirènes, Scary Mary et Skull King). La version Grandpa Beck/Blackrock games fournit en plus les baleines, le Kraken, deux cartes butin, une valeur supplémentaire par couleur (le 14) et un effet différent par pirate.</p>
<p>Pour une présentation complète, les règles sont disponibles en ligne, sur de nombreux sites : par exemple <a href="https://www.regles-du-jeu.net/regles-du-jeu-skull-king/">en texte</a> ou <a href="https://www.youtube.com/watch?v=S5C8ifEsbzk">en vidéo</a>. Pas la peine de s’étendre plus, allez les consulter pour avoir une idée des règles du jeu.</p>
<p>La boîte éditée par Schmidt :</p>
<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2025/12/skullking-schmitd.webp"><img alt="photo d'une boite de Skull King et de cartes du jeu" class="wp-image-3011" height="812" src="https://ascendances.wordpress.com/wp-content/uploads/2025/12/skullking-schmitd.webp?w=595" width="595"/></a></figure>
</div>
<p>La boîte éditée par Blackrock :</p>
<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2025/12/skullking-blackrock.webp"><img alt="photo d'une boite de Skull King et de cartes du jeu" class="wp-image-3012" height="734" src="https://ascendances.wordpress.com/wp-content/uploads/2025/12/skullking-blackrock.webp?w=595" width="595"/></a></figure>
</div>
<h3 class="wp-block-heading">En flèches et en couleurs</h3>
<p>Puisque vous avez maintenant une idée de l’ordre de priorité entre les cartes (n’est-ce pas ?), vous allez comprendre aisément les graphes orientés suivants.</p>
<p><strong>Au moins une carte baleine a été jouée :</strong></p>
<ol class="wp-block-list"></ol>
<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2025/12/sans_baleine.png"><img alt="" class="wp-image-3020" height="1023" src="https://ascendances.wordpress.com/wp-content/uploads/2025/12/sans_baleine.png?w=330" width="330"/></a></figure>
</div>
<p>Ce premier cas est le plus courant lors d’une partie.</p>
<p><strong>Aucune carte baleine n’a été jouée :</strong></p>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2025/12/avec_baleine.png"><img alt="Graphe de priorité entre les cartes si au moins une carte baleine a été jouée" class="wp-image-3019" height="480" src="https://ascendances.wordpress.com/wp-content/uploads/2025/12/avec_baleine.png?w=595" width="595"/></a></figure>
<p>Évidemment, ce cas ne peut arriver que dans une édition paquet de cartes contenant les sirènes.</p>
<h3 class="wp-block-heading">Code Source des graphes</h3>
<p>Les deux graphes ont été réalisés avec le vénérable <a href="https://graphviz.org">graphviz</a> (version 2.42.4 mais beaucoup de versions plus anciennes devraient produire le même résultat).</p>
<p><strong>Graphe sans carte baleine :</strong></p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: swift; title: ; notranslate">
digraph Jeu {
    compound=true
    fontname="Helvetica,Arial,sans-serif"
    node [fontname="Helvetica,Arial,sans-serif",style=filled]
    edge [fontname="Helvetica,Arial,sans-serif"]
	graph [style="filled"]

    subgraph cluster_pirates {
        color=firebrick1
		node [color=white]
        "premier pirate" -&gt; "autres pirates"
        label = "Pirates"
    }

    subgraph cluster_sirenes {
        color=deepskyblue
		node [color=white]
        "première sirène" -&gt; "autres sirènes"
        label = "Sirènes"
    }

    subgraph cluster_cartes_noires {
        color=black
        fontcolor=white
		node [color=white]
        label = "Cartes noires"
        c14n -&gt; cn -&gt; c1n [color=white]
    }

    subgraph cluster_cartes_jaunes {
        color=yellow
		node [color=white]
        label = "Cartes jaunes"
        c14j -&gt; cj -&gt; c1j
    }

    subgraph cluster_cartes_violettes {
		node [color=white]
        color=violetred
        label = "Cartes violettes"
        c14vi -&gt; cvi -&gt; c1vi
    }

    subgraph cluster_cartes_vertes {
		node [color=white]
        color=chartreuse3
        label = "Cartes vertes"
        c14ve -&gt; cve -&gt; c1ve
    }

    subgraph cluster_fuites {
		node [color=white]
        color=lightgrey
        label = "Fuites &amp; butins"
        "première fuite ou butin" -&gt; "autres fuites ou butins"
    }

    c1n[label="1"]
    c1j[label="1"]
    c1ve[label="1"]
    c1vi[label="1"]
    cn[label="..."]
    cj[label="..."]
    cve[label="..."]
    cvi[label="..."]
	c14n[label="14"]
    c14j[label="14"]
    c14ve[label="14"]
    c14vi[label="14"]
    "autres pirates" -&gt; "première sirène" [ltail=cluster_pirates,lhead=cluster_sirenes,minlen=2]
    "autres sirènes" -&gt; c14n [ltail=cluster_sirenes,lhead=cluster_cartes_noires,minlen=2]
    "autres sirènes" -&gt; "Skull King" [ltail=cluster_sirenes]
    "Skull King" -&gt; "premier pirate" [lhead=cluster_pirates]
    c1n -&gt; c14j [ltail=cluster_cartes_noires,lhead=cluster_cartes_jaunes,minlen=2]
    c1n -&gt; c14vi [ltail=cluster_cartes_noires,lhead=cluster_cartes_violettes,minlen=2]
    c1n -&gt; c14ve [ltail=cluster_cartes_noires,lhead=cluster_cartes_vertes,minlen=2]
    c1j -&gt; "première fuite ou butin" [ltail=cluster_cartes_jaunes,lhead=cluster_fuites,minlen=2]
    c1vi -&gt; "première fuite ou butin" [ltail=cluster_cartes_violettes,lhead=cluster_fuites,minlen=2]
    c1ve -&gt; "première fuite ou butin" [ltail=cluster_cartes_vertes,lhead=cluster_fuites,minlen=2]
}

</pre></div>
<p><strong>Graphe avec carte baleine :</strong></p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: swift; title: ; notranslate">
digraph Jeu {
    compound=true
    fontname="Helvetica,Arial,sans-serif"
    node [fontname="Helvetica,Arial,sans-serif",style=filled]
    edge [fontname="Helvetica,Arial,sans-serif"]
	graph [style="filled"]

    subgraph cluster_valeurs {
        color=orange
		node [color=white]
        label = "Cartes avec valeur"
        "premier 13" -&gt; "..."
        "premier 13" -&gt; "autres 13"
        "..." -&gt; "premier 1"
        "premier 1" -&gt; "autres 1"
    }


    subgraph cluster_autres_cartes {
		node [shape=rectangle]
        color=beige
        rank=same
        label = "Autres cartes (sauf Kraken)"
        Pirates [color=firebrick1]
        "Skull King"[color=white,shape=ellipse]
        Sirènes [color=deepskyblue]
        Fuites [color=lightgrey]
        Baleines [color=navy]
        Butins [color=gold]
    }

    "autres 1" -&gt; Sirènes [ltail=cluster_valeurs,lhead=cluster_autres_cartes,minlen=2]
}
</pre></div>
<p>(La coloration syntaxique est configurée sur <a href="https://fr.wikipedia.org/wiki/Swift_(langage_d%27Apple)">Swift</a> pour avoir un rendu à peu près correct car la coloration de code Graphviz n’est pas proposée.)</p>
<p>La génération des images se fait par une commande du type :</p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: plain; title: ; notranslate">
dot -T png sans_baleine.dot -o sans_baleine.png
</pre></div>
<p>Bonnes parties et/ou bons graphes !</p>
            </div>
        </content>
        <author>
            <name>ascendances</name>
        </author>
    </entry>
    <entry>
        <title>Utilisez Python pour vos scripts !</title>
        <link href="https://hypirion.com/musings/use-python-for-scripting" />
        <id>https://hypirion.com/musings/use-python-for-scripting</id>
        <updated>2025-12-08T16:19:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article explore pourquoi Python est un excellent choix pour l’écriture de scripts, en abordant les défis rencontrés avec d’autres outils qui peuvent se comporter différemment selon les machines ou ne pas être toujours installés. Une perspective pratique sur l’utilisation de Python comme solution de scripting fiable et cohérente.</p>
<a href="https://news.humancoders.com/t/python/items/41079-utilisez-python-pour-vos-scripts"><img src="https://hypirion.com/thumbnails/use-python-for-scripting.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/41079-utilisez-python-pour-vos-scripts#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/41079-utilisez-python-pour-vos-scripts">Utilisez Python pour vos scripts !</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Avis certification Python CodinGame</title>
        <link href="https://discuss.afpy.org/t/avis-certification-python-codingame/2892" />
        <id>https://discuss.afpy.org/t/avis-certification-python-codingame/2892</id>
        <updated>2025-12-07T08:05:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Un avis sur la certification <a href="https://www.codingame.com/take-the-test/Python3" rel="noopener nofollow ugc">Python de CodinGame</a> ?<br/>
D’après le site, on peut retenter la certification tous les mois si on a un score qui ne nous satisfait pas.</p>
<p><small>20 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/avis-certification-python-codingame/2892">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>DorianTurba</name>
        </author>
    </entry>
    <entry>
        <title>Django 6.0 : notes de version, nouveautés, compatibilité Python et changements majeurs</title>
        <link href="https://docs.djangoproject.com/en/6.0/releases/6.0/" />
        <id>https://docs.djangoproject.com/en/6.0/releases/6.0/</id>
        <updated>2025-12-05T11:07:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez les notes de version de Django 6.0 : prise en charge de Python 3.12–3.14, CSP intégré, tâches en arrière-plan et autres changements importants.</p>
<a href="https://news.humancoders.com/t/python/items/40947-django-6-0-notes-de-version-nouveautes-compatibili"><img src="https://static.djangoproject.com/img/logos/django-logo-negative.1d528e2cb5fb.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/40947-django-6-0-notes-de-version-nouveautes-compatibili#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/40947-django-6-0-notes-de-version-nouveautes-compatibili">Django 6.0 : notes de version, nouveautés, compatibilité Python et changements majeurs</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Un gestionnaire de contexte libéré, (délivré, …)</title>
        <link href="https://discuss.afpy.org/t/un-gestionnaire-de-contexte-libere-delivre/2891" />
        <id>https://discuss.afpy.org/t/un-gestionnaire-de-contexte-libere-delivre/2891</id>
        <updated>2025-12-04T16:43:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a class="mention" href="https://discuss.afpy.org/u/entwanne">@entwanne</a>, <a class="mention" href="https://discuss.afpy.org/u/debnet">@debnet</a> et moi jouons avec les gestionnaires de contextes ces temps-ci, ça m’a permis de faire ça par exemple : <a class="inline-onebox" href="https://git.afpy.org/mdk/forking">mdk/forking - La forge de l'AFPy</a></p>
<p>Le jeu du jour et d’aller plus loin dans la libération des gestionnaires de contextes, et je commence à toucher quelque chose, probablement encore un peu fragile, à peine testé, mais ça commence à marcher :</p>
<pre><code class="lang-python">import ast
import inspect
import sys
import textwrap


class Stop(Exception):
    """Internal exception to block the execution of the context body."""


class With:
    def tracer_cb(self, frame, event, arg):
        if frame is self.frame and event == "opcode":
            raise Stop

    def __enter__(self):
        current_frame = inspect.currentframe()
        self.frame = current_frame.f_back
        self.frame.f_trace = self.tracer_cb
        self.frame.f_trace_opcodes = True
        sys.settrace(self.tracer_cb)

    def execute(self, body):
        """Do whatever with the body of the with statement."""
        raise NotImplementedError

    def _locate_with_body(self, tree, lineno):
        """Locate the with statement, in tree, at lineno."""
        for node in ast.walk(tree):
            try:
                node_lineno = node.lineno
            except AttributeError:
                continue
            if node_lineno == lineno:
                return node.body

    def __exit__(self, exc_type, exc, tb):
        frame = tb.tb_frame
        src = textwrap.dedent(inspect.getsource(tb.tb_frame))
        tree = ast.parse(src)
        module = ast.Module(body=self._locate_with_body(tree, tb.tb_frame.f_lineno))
        compiled = compile(module, filename="&lt;with&gt;", mode="exec")
        Function = type(Repeat.__enter__)
        self.execute(Function(compiled, frame.f_globals, name="&lt;with&gt;"))
        return True


class Repeat(With):
    def __init__(self, times):
        self.times = times

    def execute(self, body):
        for _ in range(self.times):
            body()



with Repeat(4):
    print(42)
</code></pre>
<p><small>5 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/un-gestionnaire-de-contexte-libere-delivre/2891">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Importer 2 fois un module en Python</title>
        <link href="https://discuss.afpy.org/t/importer-2-fois-un-module-en-python/2886" />
        <id>https://discuss.afpy.org/t/importer-2-fois-un-module-en-python/2886</id>
        <updated>2025-12-04T08:36:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Petite découverte grace à un poste de Vincent Poulailleau sur linkedin : il est possible d’importer 2 fois un module Python, sans toucher à importlib:</p>
<p>Il suffit de faire le code suivant pour le voir:</p>
<pre><code class="lang-python"># fichier spam.py
print("module importé: ", __name__)
import spam
</code></pre>
<p>Si vous lancez cette commande avec <code>python spam.py</code>, il y aura 2 prints, un avec “<code>__main__</code>” et un autre avec “<code>spam</code>”.</p>
<p>Voila, j’ai découvert cette mécanique probablement inutile à la plupart, mais curieuse, récemment, donc je voulais partager <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/importer-2-fois-un-module-en-python/2886">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>DorianTurba</name>
        </author>
    </entry>
    <entry>
        <title>maj des badges pyconfr</title>
        <link href="https://discuss.afpy.org/t/maj-des-badges-pyconfr/2885" />
        <id>https://discuss.afpy.org/t/maj-des-badges-pyconfr/2885</id>
        <updated>2025-12-04T08:30:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello, les badges pyconfr sur le discuss ne semblent pas être à jour.<br/>
(d’ailleurs, est-ce possible d’avoir ceux de 23, 24 et 25 ? <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/> )</p>
<p><small>6 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/maj-des-badges-pyconfr/2885">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>DorianTurba</name>
        </author>
    </entry>
    <entry>
        <title>Serveur discord Python FR</title>
        <link href="https://discuss.afpy.org/t/serveur-discord-python-fr/2881" />
        <id>https://discuss.afpy.org/t/serveur-discord-python-fr/2881</id>
        <updated>2025-12-03T16:24:10Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Début février 2024, j’ai créé un serveur Discord pour échanger sur Python avec la communauté francophone. Resté plutôt privé un certain temps, je l’ai réanimé il y a ~7 mois.</p>
<p>Nous sommes désormais 373 membres, et le serveur tourne autour de 3 thématiques :</p>
<ul>
<li>Compétences : les sujets tournes autour de sujets comme Python, les sciences, l’architecture et le devsecops</li>
<li>Pro : on y parle recherche de job, cv et certifications</li>
<li>Compétitions : Algo et techniques, on se confronte en versus ou en collaboration sur des sites comme Genepy, Projet Euler, Advent of Code, etc.</li>
</ul>
<p>On y respecte une traduction du Code de conduite du serveur Python officiel ( <a class="inline-onebox" href="https://discord.com/invite/python" rel="noopener nofollow ugc">Python</a> ) .</p>
<p>Les différences entre le discord de l’AFPY et celui dont je parle :</p>
<ul>
<li>Plus de salons, dédié à des thématiques précises, et quand un salon n’a pas suffisamment d’intérêt/activité, il est gelé et archivé (il est possible de restaurer un salon si ça redevient pertinent à l’avenir, l’historique y est conservé),</li>
<li>un système de notification assez poussé,</li>
<li>des salons vocaux personnels et temporaires afin que les échanges puissent être multiples sans se marcher sur les pieds,</li>
<li>des notifications RSS d’articles, vidéo et forums (comme ArjanCode, l’ANSSI, r/developpeur, r/python et r/pythonfr, le discuss afpy, et StackOverflow Python),</li>
<li>un système de signalement des comportement inadaptés au discord permettant un dialogue avec la modération privé, un suivi des tickets et la génération d’un transcript accessible par l’auteur du signalement et la modération,</li>
<li>Des événements réguliers auxquels les membres peuvent s’inscrire pour y participer comme des compétitions de code, des échanges autours de l’architecture logicielle, etc.</li>
</ul>
<p>On communique sur les événements de la commu python internationale et FR, comme la PyconFR et l’Advent of Code, histoire de motiver les membres.</p>
<p>L’objectif du serveur est de rapprocher les membres de la communauté, permettant aux curieux de discuter avec d’autres devs sans risquer la toxicité de reddit, l’exposition publique de linkedin ou la rigueur de StackOverflow, le tout avec un maximum de spontanéité.</p>
<p>N’hésitez pas à nous rejoindre : <a class="inline-onebox" href="https://discord.gg/CUPSvEfX4Z" rel="noopener nofollow ugc">SWEPY</a></p>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/serveur-discord-python-fr/2881">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>DorianTurba</name>
        </author>
    </entry>
    <entry>
        <title>Invitation stand JRES 2026 à Tours</title>
        <link href="https://discuss.afpy.org/t/invitation-stand-jres-2026-a-tours/2876" />
        <id>https://discuss.afpy.org/t/invitation-stand-jres-2026-a-tours/2876</id>
        <updated>2025-11-30T18:35:10Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>La prochaine édition des JRES (Journées RÉSeaux de l’enseignement et de la recherche) aura lieu du 8 au 11 décembre 2026 au palais des congrès de Tours.<br/>
L’AFPy est invitée à y tenir un stand pour présenter notre association.<br/>
Est-ce que des membres seraient intéressé·e·s pour le faire ?</p>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/invitation-stand-jres-2026-a-tours/2876">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Package Python bug sur le fichier __init__</title>
        <link href="https://discuss.afpy.org/t/package-python-bug-sur-le-fichier-init/2874" />
        <id>https://discuss.afpy.org/t/package-python-bug-sur-le-fichier-init/2874</id>
        <updated>2025-11-26T09:21:52Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, j’ai installer mon environnement python .venv uv  avec mes package flask,openpyxl et pandas.  j’ai du du coup voulu teste s’ils marchait bien en faisant : <code>python -c “import flask; import openpyxl; print(‘OK’)”</code> mais j’ai ces erreurs que je n’arrive pas à résoudre.</p>
<p><code>File “C:\Users\FKT609835\Documents\2. ENV_TEST\Environement Python.venv\Lib\site-packages\flask_</code><em><code>init</code></em><code>_.py”, line 5, in </code><br/>
<code>from . import json as json</code><br/>
<code>File “C:\Users\FKT609835\Documents\2. ENV_TEST\Environement Python.venv\Lib\site-packages\flask\json_</code><em><code>init</code></em><code>_.py”, line 6, in </code><br/>
<code>from ..globals import current_app</code><br/>
<code>ValueError: source code string cannot contain null bytes</code></p>
<p>quelqu’un peut il m’aider sur ce sujet svp?</p>
<p><small>7 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/package-python-bug-sur-le-fichier-init/2874">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>jahel-source</name>
        </author>
    </entry>
    <entry>
        <title>Nouvelles projet py-edu-fr : formation &#34;Python initiation&#34;</title>
        <link href="https://discuss.afpy.org/t/nouvelles-projet-py-edu-fr-formation-python-initiation/2872" />
        <id>https://discuss.afpy.org/t/nouvelles-projet-py-edu-fr-formation-python-initiation/2872</id>
        <updated>2025-11-20T15:39:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>Nous allons enfin réussir à baser une formation en présentielle (pour doctorants) que nous donnons à Grenoble sur du contenu <a href="https://python-cnrs.netlify.app" rel="noopener nofollow ugc">py-edu-fr</a>! Cette session se tiendra la semaine du 15 décembre 2025, i.e. dans un peu moins d’un mois.</p>
<p>Le contenu (<a href="https://python-cnrs.netlify.app/edu/init/" rel="noopener nofollow ugc">https://python-cnrs.netlify.app/edu/init/</a>) n’est pas encore vraiment prêt (il reste notamment des TP à rajouter et il y a plein de choses à améliorer/équilibrer/repenser) mais ça commence à être montrable.</p>
<p>En tout cas, je pense que ce qu’il y a maintenant commence à permettre de voir ce que ça va donner et que des relectures seraient très utiles. Donc si ça vous intéresse et que vous avez un peu de temps, n’hésitez pas à jeter un coup d’œil et à donner votre avis (sur ce fil de discussion, par des issues <a href="https://foss.heptapod.net/py-edu-fr/py-edu-fr/-/issues" rel="noopener nofollow ugc">https://foss.heptapod.net/py-edu-fr/py-edu-fr/-/issues</a> ou même des merge requests <a href="https://python-cnrs.netlify.app/contribute" rel="noopener nofollow ugc">https://python-cnrs.netlify.app/contribute</a>).</p>
<p>Pierre</p>
<p><small>6 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/nouvelles-projet-py-edu-fr-formation-python-initiation/2872">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>paugier</name>
        </author>
    </entry>
    <entry>
        <title>[Clermont-Ferrand] Meetup mercredi 26 nov 18h30</title>
        <link href="https://discuss.afpy.org/t/clermont-ferrand-meetup-mercredi-26-nov-18h30/2868" />
        <id>https://discuss.afpy.org/t/clermont-ferrand-meetup-mercredi-26-nov-18h30/2868</id>
        <updated>2025-11-17T13:12:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Qu’est-ce que contient la nouvelle version de python ? Est-ce une version qui marque de gros changements ?<br/>
<strong>Venez tester vos connaissances sur python 3.14 au travers un quiz et du live coding</strong></p>
<p>Nous serons accueillis par nos partenaires : Coqpit qui nous met à disposition ses locaux, ainsi ITARVERNE qui nous offre de quoi poursuivre cette session autour de pizzas.</p>
<p><strong>Pas de pré-requis nécessaire,</strong> même si vous ne codez pas, venez par curiosité et vous pourrez peut-être y prendre goût.</p>
<p>Inscription gratuite mais obligatoire : <em>Je ne peux pas mettre de lien donc RDV sur le groupe PyClermont de meetup</em></p>
<p>Au plaisir de vous rencontrer</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/clermont-ferrand-meetup-mercredi-26-nov-18h30/2868/1">Meetup Quizz</a></p>
<p>2025-11-26 18:30 (Europe/Paris) → 2025-11-26 22:00 (Europe/Paris)</p>
</div>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/clermont-ferrand-meetup-mercredi-26-nov-18h30/2868">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>drigaudie</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 27 novembre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-27-novembre/2864" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-27-novembre/2864</id>
        <updated>2025-11-17T10:33:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>On se retrouve le jeudi 27 novembre pour le traditionnel meetup des retours de la PyConFR 2025 <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=15" title=":snake:" width="20"/></p>
<p>Rendez-vous dès 19h à La Cordée Valmy (métro Valmy) !</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-27-novembre/2864/1">Les retours de la PyConFR 2025</a></p>
<p>2025-11-27 19:00 (Europe/Paris) → 2025-11-27 21:30 (Europe/Paris)</p>
</div>
<p><small>4 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-27-novembre/2864">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Dearpygui 2.1.1</title>
        <link href="https://linuxfr.org/users/pas_pey/liens/dearpygui-2-1-1" />
        <id>https://linuxfr.org/users/pas_pey/liens/dearpygui-2-1-1</id>
        <updated>2025-11-15T00:36:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://pypi.org/project/dearpygui/">https://pypi.org/project/dearpygui/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140995/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/pas_pey/liens/dearpygui-2-1-1#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>pas_pey</name>
        </author>
    </entry>
    <entry>
        <title>copyparty: Portable file server</title>
        <link href="https://linuxfr.org/users/postroutine/liens/copyparty-portable-file-server" />
        <id>https://linuxfr.org/users/postroutine/liens/copyparty-portable-file-server</id>
        <updated>2025-11-14T10:08:17Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://github.com/9001/copyparty/">https://github.com/9001/copyparty/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140985/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/postroutine/liens/copyparty-portable-file-server#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Yuul B. Alwright</name>
        </author>
    </entry>
    <entry>
        <title>Débuter avec Python pour un grand débutant</title>
        <link href="https://discuss.afpy.org/t/debuter-avec-python-pour-un-grand-debutant/2860" />
        <id>https://discuss.afpy.org/t/debuter-avec-python-pour-un-grand-debutant/2860</id>
        <updated>2025-11-14T09:15:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, je viens de découvrir ce forum et je me suis inscrit car pour mon master je dois maîtriser le python, je précise que je n’ai que très peu de connaissances en informatique générale <img alt=":sweat_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/sweat_smile.png?v=15" title=":sweat_smile:" width="20"/></p>
<p>Si vous acceptez de me partager des conseils et ressources je vous en remercierais grandement !</p>
<p><small>10 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/debuter-avec-python-pour-un-grand-debutant/2860">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Libtak</name>
        </author>
    </entry>
    <entry>
        <title>S&#39;abonner au Discourse via ActivityPub</title>
        <link href="https://discuss.afpy.org/t/sabonner-au-discourse-via-activitypub/2859" />
        <id>https://discuss.afpy.org/t/sabonner-au-discourse-via-activitypub/2859</id>
        <updated>2025-11-13T10:00:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Les catégories du Discourse sont accessible via ActivityPub :</p>
<ul>
<li><a href="https://mamot.fr/@afpy@discuss.afpy.org">@afpy@discuss.afpy.org</a></li>
<li><a href="https://mamot.fr/@jobs@discuss.afpy.org">@jobs@discuss.afpy.org</a></li>
<li><a href="https://mamot.fr/@python@discuss.afpy.org">@python@discuss.afpy.org</a></li>
<li><a href="https://mamot.fr/@meetup@discuss.afpy.org">@meetup@discuss.afpy.org</a></li>
</ul>
<p>Vous pouvez vous abonner avec vos clients préférés (oui c’est un peu vide pour le moment) j’ai mis des liens mamot juste pour l’exemple.</p>
<p>Par exemple, voici ce post sur <a href="http://mamot.fr">mamot.fr</a> : <a class="inline-onebox" href="https://mamot.fr/@afpy@discuss.afpy.org/115541825405609201">Mamot - Le Mastodon de La Quadrature du Net</a></p>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sabonner-au-discourse-via-activitypub/2859">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Le dogme SESE : « Un seul return par fonction »</title>
        <link href="https://discuss.afpy.org/t/le-dogme-sese-un-seul-return-par-fonction/2858" />
        <id>https://discuss.afpy.org/t/le-dogme-sese-un-seul-return-par-fonction/2858</id>
        <updated>2025-11-13T09:44:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour les gens,</p>
<p>Je vois encore passer, en 2025, du code comme ça :</p>
<pre><code class="lang-python">def is_prime(n):
    if n &lt;= 1:
        is_prime = False
    else:
        is_prime = True
        for i in range(2, int(n**0.5) + 1):
            if n % i == 0:
                is_prime = False
    return is_prime
</code></pre>
<p>Mais <strong>POURQUOI</strong> ? (ajouter un <code>break</code> résoudrait un problème de perfs, mais il paraît que chez les vrais puristes du SESE, <code>break</code> et <code>continue</code> sont interdits aussi, peu m’importe ici, ce n’est pas mon sujet).</p>
<p>Ma question est, pourquoi ne pas l’écrire de manière lisible :</p>
<pre><code class="lang-python">def is_prime(n):
    if n == 1:
        return False
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            return False
    return True

</code></pre>
<p>Étant fan du <em>early return</em>, lire une fonction entièrement codée dans un gros <code>if</code> ou dans un gros <code>else</code> juste parce qu’on s’interdit un <code>return</code> ça me chagrine.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12260-le-return-alternatif-de-fortran-iv-1961-1" name="p-12260-le-return-alternatif-de-fortran-iv-1961-1"></a>Le return alternatif de FORTRAN IV (1961)</h2>
<p>J’ai lu quelque part que cette coutume nous viendrait des développeurs FORTRAN, qui avaient, il y a fort fort longtemps, un <a href="https://www-linac.kek.jp/cont/langinfo/web/Fortran/docs/lrm/lrm0146.htm#return_stmt">return alternatif</a>, une démo s’impose :</p>
<pre><code class="lang-fortran">   CALL CHECK(A, B, *10, *20, C)
   ...
10 ...
20 ...
   SUBROUTINE CHECK(X, Y, *, *, C)
   ...
50   IF (X) 60, 70, 80
60   RETURN
70   RETURN 1
80   RETURN 2
   END
</code></pre>
<ul>
<li>Le premier <code>RETURN</code> est un <code>return</code> normal, donc après la fin de l’exécution de la fonction <code>CHECK</code> l’exécution de la fonction qui a appelé <code>CHECK</code> reprend comme on a l’habitude.</li>
<li>Le <code>RETURN 1</code> renvoie au <strong>premier return alternatif</strong> qui vaut <code>*10</code> : donc c’est un saut au label 10.</li>
<li>Le <code>RETURN 2</code> saute au label <code>20</code> (indiquée par le <code>*20</code> côté appelant).</li>
</ul>
<p>J’imagine (probablement pas assez, ne l’ayant pas vécu) l’enfer, et la règle est apparue « <a href="https://water.usgs.gov/software/SYSDOC/code/doc/coding.pdf">Alternate RETURNs should not be used.</a> ». Le return alternatif aura vécu de 1961 (Fortran IV) à 1990 (F90), l’année de naissance de Python.</p>
<p>Et ça serait peut-être cette règle qui se serait transformée en « un seul return par fonction » qui pollue encore notre code de nos jours.</p>
<p>Clairement « plusieurs return » (différents points de sortie dans la fonction appelée) et « return altenatifs » (plusieurs points d’atterrissage dans la fonction appelante) n’ont rien à voir : on ne peut pas « sauver » la règle <em>Single-Exit</em> en la réécrivant « un seul return par fonction ».</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12260-lentre-alternative-de-fortran-2" name="p-12260-lentre-alternative-de-fortran-2"></a>L’entrée alternative de FORTRAN</h2>
<p>Dans <em>Single-Entry Single-Exit</em> (<em>SESE</em>) on lit <em>single-entry</em>, tiens c’est quoi ça ?</p>
<p>Ça date de la même époque, en FORTRAN il existait un mot clé <a href="https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn99/index.html"><code>ENTRY</code></a> permettant d’ajouter des points d’entrée alternatifs à une fonction.</p>
<p>Le fait que <em>Single-Entry</em> signifie « n’utilisez pas de points d’entrée alternatifs » me conforte dans l’idée que <em>Single-Exit</em> signifie « n’utilisez pas de return alternatifs ».</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12260-le-dogme-3" name="p-12260-le-dogme-3"></a>Le dogme</h2>
<p>Si c’est le cas, c’est donc littéralement un dogme, j’imagine la scène :</p>
<blockquote>
<p>Dis, Maître, pourquoi SonarCube dit qu’il faut pas deux return dans ma fonction ?</p>
</blockquote>
<blockquote>
<p>La sagesse des anciens dit « Single-Entry, Single-Exit ». Nous on fait du code de qualité, on respecte la sagesse des anciens, on respecte MISRA et l’IEC 61508, sécurité, maintenabilité, lisibilité ! Si t’es contre t’es un jeune qui va droit dans le mur, je te le dis moi, y’en a qu’on essayé, ils ont eu des problèmes… Si tu ne veux pas finir comme les développeurs du THERAC 25, réécrit ta fonction à la norme et pose pas de questions.</p>
</blockquote>
<blockquote>
<p>Maître, c’est quoi alors Single-Entry ?</p>
</blockquote>
<blockquote>
<p>J’sais pas, retourne bosser, respecte la norme, et pose pas d’questions.</p>
</blockquote>
<p>Alors que SESE ne peut pas s’appliquer aux langages qui n’ont pas d’entrée alternatives ou de return alternatifs, la règle ne peut s’appliquer à <strong>aucun</strong> langage contemporain (même fortran depuis F90 n’a plus ni l’un, ni l’autre).</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12260-le-dogme-survit-4" name="p-12260-le-dogme-survit-4"></a>Le dogme survit</h2>
<p>Les tenant du « un seul return » se sont convaincus, et le font vivre, avec des arguments variés :</p>
<ul>
<li><a href="https://next.sonarqube.com/sonarqube/coding_rules?open=c%3AS1005&amp;rule_key=c%3AS1005">MISRA a dit que</a></li>
<li>L’IEC 61508 a dit que.</li>
<li><a href="https://www.cs.utexas.edu/~EWD/transcriptions/EWD02xx/EWD249/EWD249.html">Dijkstra a dit que</a>, rep à ça !</li>
<li>Ça permet de mettre un <code>assert</code> au moment du <code>return</code>.</li>
<li>Ça permet de mettre un <code>breakpoint</code> au moment du <code>return</code>.</li>
<li>Ça permet de libérer des ressources au moment du <code>return</code>.</li>
<li>Le code après un <code>return</code> pourrait ne pas être exécuté.</li>
<li>…</li>
</ul>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12260-ma-conclusion-5" name="p-12260-ma-conclusion-5"></a>Ma conclusion</h2>
<p>Libérez-vous des dogmes des années 70 !</p>
<p>Rédigez le code qui est le plus lisible à vos yeux en utilisant tous les outils à votre disposition pour ça. Si ça implique parfois de n’utiliser qu’un seul return, d’accord.</p>
<p>Mais si ça implique de tordre le code pour arriver à un seul <code>return</code>, pas d’accord.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-12260-plus-de-lecture-6" name="p-12260-plus-de-lecture-6"></a>Plus de lecture</h2>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon"/>
<a href="https://www.web-dev-qa-db-fra.com/coding-style/dou-vient-la-notion-de-un-seul-retour/1079071304/" rel="noopener" target="_blank">web-dev-qa-db-fra.com</a>
</header>
<article class="onebox-body">
<h3><a href="https://www.web-dev-qa-db-fra.com/coding-style/dou-vient-la-notion-de-un-seul-retour/1079071304/" rel="noopener" target="_blank">[RÉSOLUE] coding-style: D'où vient la notion de "un seul retour"? -...</a></h3>
<p>Je parle souvent aux programmeurs qui disent "Ne mettez pas plusieurs déclarations de retour dans la même méthode." Quand je leur demande de me dire les raisons, tout ce que je reçois est "Le codage standard le dit. "ou" C'est déroutant. "Quand ...</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<aside class="onebox allowlistedgeneric">
<header class="source">
<a href="https://www.anthonysteele.co.uk/TheSingleReturnLaw" rel="noopener" target="_blank">Anthony Steele</a>
</header>
<article class="onebox-body">
<h3><a href="https://www.anthonysteele.co.uk/TheSingleReturnLaw" rel="noopener" target="_blank">The Single Return Law</a></h3>
<p>Bloggy</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<aside class="onebox pdf">
<header class="source">
<a href="https://meetingcpp.com/mcpp/slides/2022/Single_entry_single_exit_a_closer_look_at_the_rule5405.pdf" rel="noopener" target="_blank">meetingcpp.com</a>
</header>
<article class="onebox-body">
<a href="https://meetingcpp.com/mcpp/slides/2022/Single_entry_single_exit_a_closer_look_at_the_rule5405.pdf" rel="noopener" target="_blank"><span class="pdf-onebox-logo"></span></a>
<h3><a href="https://meetingcpp.com/mcpp/slides/2022/Single_entry_single_exit_a_closer_look_at_the_rule5405.pdf" rel="noopener" target="_blank">Single_entry_single_exit_a_closer_look_at_the_rule5405.pdf</a></h3>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<aside class="onebox allowlistedgeneric">
<header class="source">
<a href="https://web.archive.org/web/20110223060848/http://www.leepoint.net/JavaBasics/methods/method-commentary/methcom-30-multiple-return.html" rel="noopener" target="_blank">web.archive.org</a>
</header>
<article class="onebox-body">
<h3><a href="https://web.archive.org/web/20110223060848/http://www.leepoint.net/JavaBasics/methods/method-commentary/methcom-30-multiple-return.html" rel="noopener" target="_blank">Java Basics: Commentary: Return statements and the single exit fantasy</a></h3>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<aside class="onebox stackexchange">
<header class="source">
<a href="https://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement" rel="noopener" target="_blank">stackoverflow.com</a>
</header>
<article class="onebox-body">
<a href="https://stackoverflow.com/users/381/david" rel="noopener" target="_blank">
<img alt="David" class="thumbnail onebox-avatar" height="256" src="https://www.gravatar.com/avatar/8d97f1496e5d1aa2ea95184f80425897?s=256&amp;d=identicon&amp;r=PG" width="256"/>
</a>
<h4>
<a href="https://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement" rel="noopener" target="_blank">Should a function have only one return statement?</a>
</h4>
<div class="tags">
<strong>language-agnostic, coding-style</strong>
</div>
<div class="date">
  asked by
  
  <a href="https://stackoverflow.com/users/381/david" rel="noopener" target="_blank">
    David
  </a>
  on <a href="https://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement" rel="noopener" target="_blank">09:26AM - 31 Aug 08 UTC</a>
</div>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p><small>7 messages - 6 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/le-dogme-sese-un-seul-return-par-fonction/2858">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Canaille passe en version bêta</title>
        <link href="https://yaal.coop/blog/canaille-beta" />
        <id>https://yaal.coop/blog/canaille-beta</id>
        <updated>2025-11-12T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Nos derniers travaux sur Canaille financés par la <a href="https://nlnet.nl">fondation NLNet</a> nous amènent à sortir une version bêta. Faisons le point.</p>
<h1>Derniers travaux</h1>
<h2>Gestionnaire de tâches</h2>
<p>Nous avons implémenté un gestionnaire de tâches qui permet à Canaille d'effectuer les tâches longues de manière asynchrone.
C'est utilisé notamment pour propager les requêtes <a href="https://scim.libre.sh">SCIM</a> ou les envois de mail.
L'implémentation utilise <a href="https://dramatiq.io">dramatiq</a>, et nous avons publié le paquet <a href="https://codeberg.org/yaal/dramatiq-eager-broker">dramatiq-eager-broker</a> qui permet de conserver un comportement synchrone dans la suite de tests, et dans le cas où le gestionnaire de tâches ne serait pas configuré.</p>
<h2>Certification OpenID Connect</h2>
<p><a href="https://yaal.coop/blog/feeds/canaille-oidc-certification">Nous vous en parlions récemment</a>, Canaille a obtenu au mois de septembre dernier la certification de la fondation OpenID Connect.
Cela garanti que Canaille a un comportement conforme pour la plupart des opérations OpenID Connect courantes.</p>
<p><a href="https://openid.net/developers/certified-openid-connect-implementations/"><img alt="Canaille OIDC certification" src="https://yaal.coop/media/blog/articles/canaille-oidc-certification.png"/></a></p>
<p>Le processus de certification a révélé beaucoup d'erreurs d'interprétation, souvent mineures mais parfois importantes.
Nous avons corrigé la plupart des problèmes directement dans <a href="https://github.com/authlib/authlib">Authlib</a>, la bibliothèque sous-jacente d'implémentation des normes.</p>
<h2>Securité</h2>
<p>Nous avons implémenté les recommandations restantes issues de l'audit de <a href="https://www.radicallyopensecurity.com">Radically Open Security</a>.
La plupart étaient des recommandations mineures relevant des bonnes pratiques, mais il y avait tout de même une vulnérabilité à niveau de risque élevé.
Tout est corrigé désormais. <a href="https://yaal.coop/media/blog/articles/NGIE Canaille penetration test report 2025 1.0.pdf">Voici le rapport de sécurité</a>.
Nous avons aussi <a href="https://canaille.readthedocs.io/fr/latest/references/security.html">documenté</a> les <a href="https://cyber.gouv.fr/publications/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe">recommandations de l'ANSSI</a> concernant l'authentification et la gestion des mots de passe, que Canaille implémente.
La plupart des recommandations sont implémentées, il reste principalement à <a href="https://gitlab.com/yaal/canaille/-/issues/296">supporter WebAuthn</a>.</p>
<h2>Documentation</h2>
<p>Nous travaillons continuellement sur la documentation, et visons de suivre les recommandations de <a href="https://diataxis.fr">Diátaxis</a>.
Nous avons écrit des chapitres pour <a href="https://canaille.readthedocs.io/fr/latest/tutorials/getting-started.html">le premier lancement de Canaille</a> et la <a href="https://canaille.readthedocs.io/en/latest/tutorials/oidc-client.html">configuration du premier client OpenID Connect</a>.
Ces premières étapes nous indirectement fait travailler sur <a href="https://github.com/jag-k/pydantic-settings-export">pydantic-settings-export</a>, qui permet notamment aux utilisateurs d'exporter un fichier de configuration avec toutes les valeurs par défaut commentées et décrites, ce qui offre un bon point de départ pour commencer à adapter la configuration. Nous utilisons encore une implémentation personnalisée, le temps de faire remonter toutes les modifications dont nous avons besoin dans le projet original.</p>
<h1>La suite</h1>
<p>Canaille vise la simplicité et son périmètre fonctionnel est donc assez restreint.
Nous limitons donc le nombre de fonctionnalités que nous souhaitons implémenter, cepedant il en reste quelques unes :</p>
<ul>
<li>Le <a href="https://gitlab.com/yaal/canaille/-/issues/296">support de WebAuthn</a> comme facteur d'authentification.
  Cela nous permettra d'implémenter les dernières recommandations de l'ANSSI qui manquent.</li>
<li>Le <a href="https://gitlab.com/yaal/canaille/-/issues/211">support d'une méthode de Captcha</a>.
  Il est à première vue étonnant d'inclure cette fonctionnalité à l'heure où la pertinence des Captchas s'amoindrit avec l'apparition des IAs.
  Nous notons cependant que c'est une fonctionnalité essentielles pour certains utilisateurs, comme en témoigne le <a href="https://lacontrevoie.fr/blog/2024/comparatif-de-onze-solutions-de-sso-libres">comparatif très poussé de solutions de SSO libres</a> publié par la Contre-Voie l'année dernière.</li>
<li>L'implémentation d'un système de <a href="https://gitlab.com/yaal/canaille/-/issues/301">greffons personnalisés pour Canaille</a>.
  C'est à un horizon plus lointain, mais nous aimerions proposer une API pour que des développeurs puissent implémenter leur propre facteur d'authentification pour Canaille, ou bien leur propre connecteur de base de données.</li>
</ul>
<p>À par ces fonctionnalités visibles, l'essentiel des évolutions à venir viendra sous le capot :</p>
<ul>
<li>L'amélioration de la <a href="https://github.com/python-scim">pile SCIM</a>, notamment pour apporter le support des <a href="https://gitlab.com/yaal/canaille/-/issues/274">filtres SCIM</a>.</li>
<li>L'amélioration de la <a href="https://github.com/authlib/authlib">pile OIDC</a> pour apporter le support de nouvelles normes.
  Notamment celles qui ont a trait à la <a href="https://gitlab.com/yaal/canaille/-/issues/155">déconnexion centralisée</a> ou bien à la sécurité.</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Canaille beta is out</title>
        <link href="https://yaal.coop/blog/en/canaille-beta" />
        <id>https://yaal.coop/blog/en/canaille-beta</id>
        <updated>2025-11-12T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Our recent work on Canaille funded by <a href="https://nlnet.nl">NLNet Foundation</a> brings us to release a beta version. Let's have a look on what changed.</p>
<h1>Recent Work</h1>
<h2>Task Manager</h2>
<p>We implemented a task manager that allows Canaille to perform long-running tasks asynchronously.
This is notably used to propagate <a href="https://scim.libre.sh">SCIM</a> requests or send emails.
The implementation uses <a href="https://dramatiq.io">dramatiq</a>, and we published the <a href="https://codeberg.org/yaal/dramatiq-eager-broker">dramatiq-eager-broker</a> package which allows maintaining synchronous behavior in the test suite, and when the task manager is not configured.</p>
<h2>OpenID Connect Certification</h2>
<p>As we <a href="https://yaal.coop/blog/feeds/canaille-oidc-certification">mentioned recently</a>, Canaille obtained OpenID Connect Foundation certification last September.
This guarantees that Canaille behaves in compliance with most common OpenID Connect operations.</p>
<p><a href="https://openid.net/developers/certified-openid-connect-implementations/"><img alt="Canaille OIDC certification" src="https://yaal.coop/media/blog/articles/canaille-oidc-certification.png"/></a></p>
<p>The certification process revealed many interpretation errors, often minor but sometimes significant.
We fixed most issues directly in <a href="https://github.com/authlib/authlib">Authlib</a>, the underlying library implementing the standards.</p>
<h2>Security</h2>
<p>We implemented the remaining recommendations from the <a href="https://www.radicallyopensecurity.com">Radically Open Security</a> audit.
Most were minor recommendations following best practices, but there was a high threat finding. Now everything is now in place. <a href="https://yaal.coop/media/blog/articles/NGIE Canaille penetration test report 2025 1.0.pdf">You can have a look at the report</a>.
We also <a href="https://canaille.readthedocs.io/en/latest/references/security.html">documented</a> the <a href="https://cyber.gouv.fr/publications/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe">ANSSI recommendations</a> regarding authentication and password management, which Canaille implements.
Most recommendations are implemented, the main remaining task is to <a href="https://gitlab.com/yaal/canaille/-/issues/296">support WebAuthn</a>.</p>
<h2>Documentation</h2>
<p>We continuously work on documentation, aiming to follow <a href="https://diataxis.fr">Diátaxis</a> recommendations.
We wrote chapters for <a href="https://canaille.readthedocs.io/en/latest/tutorials/getting-started.html">getting started with Canaille</a> and <a href="https://canaille.readthedocs.io/en/latest/tutorials/oidc-client.html">configuring the first OpenID Connect client</a>.
These initial steps indirectly led us to work on <a href="https://github.com/jag-k/pydantic-settings-export">pydantic-settings-export</a>, which notably allows users to export a configuration file with all default values commented and described, providing a good starting point to begin adapting the configuration. We're still using a custom implementation while we upstream all the changes we need to the original project.</p>
<h1>What's Next</h1>
<p>Canaille aims for simplicity and its functional scope is therefore quite limited.
We thus limit the number of features we want to implement, however a few remain:</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/issues/296">WebAuthn support</a> as an authentication factor.
  This will allow us to implement the last missing ANSSI recommendations.</li>
<li><a href="https://gitlab.com/yaal/canaille/-/issues/211">Captcha method support</a>.
  At first glance it's surprising to include this feature at a time when the relevance of Captchas is diminishing with the emergence of AIs.
  However, we note that this is an essential feature for some users, as evidenced by the <a href="https://lacontrevoie.fr/blog/2024/comparatif-de-onze-solutions-de-sso-libres">very thorough comparison of open source SSO solutions</a> published by La Contre-Voie last year.</li>
<li>Implementation of a <a href="https://gitlab.com/yaal/canaille/-/issues/301">custom plugin system for Canaille</a>.
  This is on a more distant horizon, but we would like to offer an API so developers can implement their own authentication factor for Canaille, or their own database connector.</li>
</ul>
<p>Besides these visible features, most upcoming developments will be under the hood:</p>
<ul>
<li>Improving the <a href="https://github.com/python-scim">SCIM stack</a>, notably to bring support for <a href="https://gitlab.com/yaal/canaille/-/issues/274">SCIM filters</a>.</li>
<li>Improving the <a href="https://github.com/authlib/authlib">OIDC stack</a> to bring support for new standards.
  Particularly those related to <a href="https://gitlab.com/yaal/canaille/-/issues/155">centralized logout</a> or security.</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Sur Grenoble - Meetup le 20 novembre</title>
        <link href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-20-novembre/2857" />
        <id>https://discuss.afpy.org/t/sur-grenoble-meetup-le-20-novembre/2857</id>
        <updated>2025-11-11T18:47:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>On organise à Grenoble jeudi 20 novembre 2025 un Meetup Python pour présenter un retour sur la PyData et la PyConFR.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-20-novembre/2857/1">Retour sur les conférences Pyconfr et PyData</a></p>
<p>2025-11-20 19:00 (Europe/Paris) → 2025-11-20 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-grenoble-meetup-le-20-novembre/2857">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Pierre-Loic</name>
        </author>
    </entry>
    <entry>
        <title>Libusb-UVC : une bibliothèque Python pure pour les caméras USB Video Class</title>
        <link href="https://linuxfr.org/users/freejeff/journaux/libusb-uvc-une-bibliotheque-python-pure-pour-les-cameras-usb-video-class" />
        <id>https://linuxfr.org/users/freejeff/journaux/libusb-uvc-une-bibliotheque-python-pure-pour-les-cameras-usb-video-class</id>
        <updated>2025-11-08T15:25:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Le protocole <strong>UVC</strong> (<em>USB Video Class</em>) définit la façon dont une caméra expose ses flux vidéo et ses contrôles à travers l’USB.<br/>
Il s’agit d’un protocole <strong>standardisé par l’USB-IF</strong>, utilisé par la quasi-totalité des webcams modernes : caméras internes de portables, modules USB, microscopes numériques, etc.<br/>
Sur Linux, c’est habituellement le module noyau <code>uvcvideo</code> qui gère ces périphériques et fournit une interface <code>/dev/video*</code> à travers <strong>V4L2</strong>.</p>
<p>Mais dans certains cas, on a besoin d’un accès <strong>plus bas-niveau</strong>, directement via <code>libusb</code> :<br/>
pour expérimenter des contrôles propriétaires, récupérer des images fixes (<code>still image capture</code>), inspecter les descripteurs, ou encore gérer des flux compressés que V4L2 ne supporte pas encore (H.265, VP8, AV1…).</p>
<p>C’est dans ce contexte qu’est née <strong><a href="https://github.com/jeffwitz/Libusb-UVC">Libusb-UVC</a></strong>.</p>
<hr/>
<h3 id="toc-objectif-du-projet">Objectif du projet</h3>
<p><code>Libusb-UVC</code> vise à fournir une <strong>implémentation Python pure</strong> du protocole UVC :</p>
<ul>
<li>indépendante du pilote noyau (<code>uvcvideo</code> peut rester chargé),</li>
<li>pilotable entièrement en espace utilisateur via <strong>libusb</strong>,</li>
<li>avec une API orientée objet et un outillage d’inspection complet.</li>
</ul>
<p>Le but n’est pas de remplacer V4L2, mais de <strong>comprendre et explorer le protocole</strong> depuis l’espace utilisateur, pour le contrôle, le streaming et l’expérimentation.</p>
<hr/>
<h3 id="toc-ce-que-fait-la-bibliothèque-aujourdhui">Ce que fait la bibliothèque aujourd’hui</h3>
<ul>
<li><p><strong>Streaming complet en userspace</strong><br/>
Le module gère les flux <strong>YUYV</strong> et <strong>MJPEG</strong> en temps réel, avec reconstruction des trames, gestion de l’isochronisme et du changement d’alt-setting.<br/>
Les flux <strong>compressés</strong> (H.264, H.265, VPx, AV1…) sont <strong>également pris en charge</strong> en mode <em>pass-through</em> : la bibliothèque ne les décode pas, mais fournit les paquets bruts aux décodeurs en espace utilisateur (par exemple <strong>PyAV</strong> ou <strong>GStreamer</strong>).</p></li>
<li><p><strong>Contrôles vidéo complets (VC)</strong><br/>
Les unités standard (Input Terminal, Processing Unit) et les <strong>Extension Units</strong> propriétaires sont découvertes dynamiquement et peuvent être interrogées ou modifiées (<code>GET_CUR</code>, <code>SET_CUR</code>, etc.).<br/>
Un système de fichiers <strong>quirks JSON</strong> permet de documenter les GUIDs connus et de donner des noms explicites aux sélecteurs (par exemple les GUID Quanta ou Microsoft XU).</p></li>
<li><p><strong>Gestion des images fixes (<code>Still Image Capture</code>)</strong><br/>
Le protocole UVC 1.1 introduit la possibilité pour une caméra de capturer une <strong>image unique à la demande</strong>, avec éventuellement une résolution différente du flux vidéo.<br/>
Cette fonctionnalité a été implémentée : la bibliothèque sait envoyer la commande <code>STILL_IMAGE_TRIGGER</code> et récupérer la trame correspondante.<br/>
En pratique, <strong>aucune caméra testée jusqu’ici</strong> ne semble exposer de vrai mode <code>still image</code>, même si beaucoup déclarent les descripteurs correspondants.<br/>
Cela reste donc surtout une <strong>partie exploratoire</strong> du protocole, mais elle est fonctionnelle côté code.</p></li>
<li><p><strong>Mode hybride avec le pilote du noyau</strong><br/>
Si <code>uvcvideo</code> est chargé, la bibliothèque peut <strong>détacher uniquement l’interface de contrôle (VC)</strong> pour lire ou écrire les paramètres sans perturber les applications utilisant <code>/dev/video*</code>.<br/>
Le flux vidéo reste alors accessible via les outils classiques, ce qui permet un diagnostic fin sans avoir à décharger de module.</p></li>
<li><p><strong>Inspection et génération de profils (<code>quirks</code>)</strong><br/>
L’outil <code>pyusb_uvc_info.py</code> permet d’afficher toutes les interfaces, formats, résolutions et contrôles d’une caméra.<br/>
Il peut aussi générer un fichier JSON décrivant la structure de ses XU, utile pour la documentation ou le débogage.</p></li>
</ul>
<hr/>
<h3 id="toc-particularités-et-différences-avec-pyuvc">Particularités et différences avec pyuvc</h3>
<p>Contrairement à <code>pyuvc</code> (qui repose sur le pilote V4L2 et sur <code>libjpeg-turbo</code> pour le décodage MJPEG),<br/>
<code>Libusb-UVC</code> ne s’appuie sur <strong>aucun pilote noyau</strong>.<br/>
Tout est géré via les transferts USB, en Python pur, ce qui permet de manipuler des flux que V4L2 ignore encore (par exemple des flux <strong>compressés modernes</strong>).</p>
<p>Pour le décodage, la bibliothèque peut déléguer à :</p>
<ul>
<li>
<strong>PyAV</strong> (binding FFmpeg) pour le décodage logiciel ou matériel,</li>
<li>
<strong>GStreamer</strong> (via <code>appsrc</code>) pour des pipelines plus complexes,
tout en restant agnostique sur le backend.</li>
</ul>
<p>Ce choix rend la bibliothèque <strong>beaucoup plus flexible</strong> que pyuvc, notamment pour des usages d’analyse ou de recherche.</p>
<hr/>
<h3 id="toc-perspectives">Perspectives</h3>
<p>Les prochaines étapes concernent :</p>
<ul>
<li>la validation de nouveaux GUIDs d’Extension Units (Quanta, Realtek, Microsoft),</li>
<li>et la consolidation de la documentation technique (schémas des descripteurs, exemples de commandes <code>GET_LEN</code> et <code>GET_INFO</code>).</li>
</ul>
<p>Avec Libusb-UVC, on a un <strong>outil libre et reproductible</strong> pour explorer le protocole UVC, comprendre les caméras, et permettre à d’autres de bâtir dessus.</p>
<hr/>
<h3 id="toc-code-et-documentation">Code et documentation</h3>
<ul>
<li>
<strong>Code source :</strong> <a href="https://github.com/jeffwitz/Libusb-UVC">github.com/jeffwitz/Libusb-UVC</a>
</li>
<li>
<strong>Licence :</strong> MIT</li>
<li>
<strong>Langage :</strong> Python ≥ 3.8</li>
<li>
<strong>Dépendance principale :</strong> libusb1</li>
<li>
<strong>Exemples fournis :</strong> inspection, capture d’image, capture vidéo, génération de quirks</li>
</ul>
<hr/>
<h3 id="toc-conclusion">Conclusion</h3>
<p><code>Libusb-UVC</code> offre un regard complet sur le protocole UVC depuis l’espace utilisateur.<br/>
C’est un outil utile pour les chercheurs, makers ou développeurs qui veulent comprendre comment une caméra dialogue réellement sur le bus USB —<br/>
et un bon point de départ pour aller au-delà de ce que propose V4L2.</p>
<div><a href="https://linuxfr.org/users/freejeff/journaux/libusb-uvc-une-bibliotheque-python-pure-pour-les-cameras-usb-video-class.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140923/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/freejeff/journaux/libusb-uvc-une-bibliotheque-python-pure-pour-les-cameras-usb-video-class#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>freejeff</name>
        </author>
    </entry>
    <entry>
        <title>TIL: le module `compression`</title>
        <link href="https://discuss.afpy.org/t/til-le-module-compression/2853" />
        <id>https://discuss.afpy.org/t/til-le-module-compression/2853</id>
        <updated>2025-11-08T09:51:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon" height="16" src="https://docs.python.org/3/_static/py.svg" width="16"/>
<a href="https://docs.python.org/3/library/compression.html" rel="noopener" target="_blank">Python documentation</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img alt="" class="thumbnail" height="361" src="https://docs.python.org/3.14/_images/social_previews/summary_library_compression_ae35af9e.png" width="690"/></div>
<h3><a href="https://docs.python.org/3/library/compression.html" rel="noopener" target="_blank">The compression package</a></h3>
<p>The compression package contains the canonical compression modules containing interfaces to several different compression algorithms. Some of these modules have historically been available as separ...</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>J’aime bien le fait que tous les modules de compression aient la même API <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=15" title=":slight_smile:" width="20"/></p>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/til-le-module-compression/2853">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Impression document PDF dans une application PySide 6</title>
        <link href="https://discuss.afpy.org/t/impression-document-pdf-dans-une-application-pyside-6/2844" />
        <id>https://discuss.afpy.org/t/impression-document-pdf-dans-une-application-pyside-6/2844</id>
        <updated>2025-11-06T13:00:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je suis en train de concevoir une application avec PySide 6, cette application génère un fichier pdf que je charge dans un QPdfDocument puis dans un QPdfView afin que l’utilisateur puisse le visualiser, je veux ensuite lui permettre de l’imprimer, mais je n’arrive pas à réaliser cette partie, c’est à dire celle de l’impression, j’ai essayé plusieurs solutions trouvées sur internet mais aucune ne marche, je suis juste arrivé à imprimer mais le fichier imprimé ne correspond pas à la taille ni la résolution voulue (A5). Je souhaiterais idéalement permettre une prévisualisation de la page à imprimer dans la boite de dialogue à imprimer.</p>
<p>Mise à jour (Ajout du code source pour aider):</p>
<pre><code class="lang-python">        self.pdf_document=QPdfDocument()
        self.pdf_document.load("uploads/certificates/good_health_certificate.pdf")

        w=QWidget()
        main_layout=QVBoxLayout()
        w.setLayout(main_layout)
        self.pdf_view = QPdfView()
        #self.pdf_view.setPageMode(QPdfView.PageMode.MultiPage)
        self.pdf_view.setDocument(self.pdf_document)
        main_layout.addWidget(self.pdf_view)
        
        buttons_layout=QHBoxLayout()
        
        button=QPushButton("Zoom +")
        button.clicked.connect(self.set_zoom_plus)
        buttons_layout.addWidget(button)

        button=QPushButton("Zoom -")
        button.clicked.connect(self.set_zoom_moins)
        buttons_layout.addWidget(button)

        main_layout.addLayout(buttons_layout)

        button=QPushButton("Imprimer")
        button.clicked.connect(self.print_certificate)
        main_layout.addWidget(button)

        self.setCentralWidget(w)
        
        self.zoom_value=1

    def set_zoom_plus(self):
        self.zoom_value+=0.1
        self.pdf_view.setZoomFactor(self.zoom_value)

    def set_zoom_moins(self):
        self.zoom_value-=0.1
        self.pdf_view.setZoomFactor(self.zoom_value)
    
    
    def print_certificate(self):
        if self.pdf_document.status()!=QPdfDocument.Status.Ready:
            return
        printer=QPrinter()
        dialog=QPrintDialog(printer, self)

        if dialog.exec():
            painter=QPainter(printer)

            for page in range(self.pdf_document.pageCount()):
                image=self.pdf_document.render(page)
                rect=painter.viewport()
                image_scaled=image.scaled(rect.size(), aspectMode=1)
                painter.drawImage(rect.topLeft(), image)

                if page &lt; self.pdf_document.pageCount()-1:
                    printer.newPage()
            painter.end()
</code></pre>
<p>Voici le code (ci-dessus) que j’ai obtenu en cherchant sur le net, mais ça ne fonctionne pas.</p>
<p>Merci par avance.</p>
<p><small>2 messages - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/impression-document-pdf-dans-une-application-pyside-6/2844">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mahmoud</name>
        </author>
    </entry>
    <entry>
        <title>Python et GRAFCET</title>
        <link href="https://discuss.afpy.org/t/python-et-grafcet/2842" />
        <id>https://discuss.afpy.org/t/python-et-grafcet/2842</id>
        <updated>2025-11-06T06:27:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour</p>
<p>je suis nouveau sur ce forum, et utilisateur occasionnel de python.</p>
<p>Je m’interroge sur la possibilité d’utiliser Python pour programmer du GRAFCET notamment sur des cartes type Raspberry PI.</p>
<p>En théorie, le GRAFCET n’est autre qu’un graphe assez proche des réseaux de Pétri et des machines à états finis et j’ai vu qu’il y avait des modules pythons.</p>
<p>Si quelqu’un a déjà fait l’expérience sur ce sujet, je l’en remercie.</p>
<p>Cordialement</p>
<p>François-Marie</p>
<p><small>9 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/python-et-grafcet/2842">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Billard</name>
        </author>
    </entry>
    <entry>
        <title>Gestionnaire de contexte qui ne s&#39;exécute pas</title>
        <link href="https://discuss.afpy.org/t/gestionnaire-de-contexte-qui-ne-sexecute-pas/2839" />
        <id>https://discuss.afpy.org/t/gestionnaire-de-contexte-qui-ne-sexecute-pas/2839</id>
        <updated>2025-11-05T09:12:01Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Challenge du matin :</p>
<pre><code class="lang-python">with DoNotRun():
    print("Is never printed")
</code></pre>
<p>Oui je sais que <code>if False:</code> existe, mais j’aimerai vraiment un <code>with</code> pas un <code>if </code> ici.</p>
<p><small>28 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/gestionnaire-de-contexte-qui-ne-sexecute-pas/2839">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>protéger ses passwords de comptes privés</title>
        <link href="https://linuxfr.org/forums/linux-debutant/posts/proteger-ses-passwords-de-comptes-prives" />
        <id>https://linuxfr.org/forums/linux-debutant/posts/proteger-ses-passwords-de-comptes-prives</id>
        <updated>2025-11-04T07:13:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>Merci par avance pour vos aides!<br/>
Je m'explique, j'ai un serveur sous ubuntu. Il n'y a que un compte admin pour le moment.<br/>
J'ai fais appel à un stagiaire codeur pour créer et installer des codes python pour gérer Instagram notamment, installer des app sous ubuntu, modifier des fichiers comme Crontab,… </p>
<p>Comment faire pour avoir mes mots de passe de comptes privés tel que Instagram sans les dévoiler au codeur mais qu'il puisse faire fonctionner ces codes? Faàon fichier .env ou autre ? merci</p>
<div><a href="https://linuxfr.org/forums/linux-debutant/posts/proteger-ses-passwords-de-comptes-prives.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140879/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-debutant/posts/proteger-ses-passwords-de-comptes-prives#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>thomas75</name>
        </author>
    </entry>
    <entry>
        <title>Language performance</title>
        <link href="https://linuxfr.org/users/yboy360/liens/language-performance" />
        <id>https://linuxfr.org/users/yboy360/liens/language-performance</id>
        <updated>2025-11-03T20:57:57Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://pez.github.io/languages-visualizations/#loops">https://pez.github.io/languages-visualizations/#loops</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140878/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/yboy360/liens/language-performance#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>YBoy360</name>
        </author>
    </entry>
    <entry>
        <title>Sur Strasbourg - des intéressés ?</title>
        <link href="https://discuss.afpy.org/t/sur-strasbourg-des-interesses/2830" />
        <id>https://discuss.afpy.org/t/sur-strasbourg-des-interesses/2830</id>
        <updated>2025-11-03T09:02:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello. Suite à la pyconf, je propose que tout le monde déménage à Strasbourg pour redynamiser les rencontres à Strasbourg. En attendant pour ceux qui sont déjà du côté de Strasbourg, je propose qu’on se voit un jeudi soir à 20h. Une idée de lieu qui pourrait satisfaire tout le monde ?</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-strasbourg-des-interesses/2830/1">Meetup sur Strasbourg</a></p>
<p>2025-11-20 20:00 (Europe/Paris) → 2025-11-20 22:00 (Europe/Paris)</p>
</div>
<p><small>18 messages - 8 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-strasbourg-des-interesses/2830">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>vincent67</name>
        </author>
    </entry>
    <entry>
        <title>La fondation Python renonce à une subvention plutôt qu&#39;à ses valeurs (DEI)</title>
        <link href="https://linuxfr.org/users/wilk/liens/la-fondation-python-renonce-a-une-subvention-plutot-qu-a-ses-valeurs-dei" />
        <id>https://linuxfr.org/users/wilk/liens/la-fondation-python-renonce-a-une-subvention-plutot-qu-a-ses-valeurs-dei</id>
        <updated>2025-11-01T11:25:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.zdnet.fr/blogs/l-esprit-libre/la-fondation-python-renonce-a-une-subvention-de-15-million-de-dollars-plutot-qua-ses-valeurs-484243.htm">https://www.zdnet.fr/blogs/l-esprit-libre/la-fondation-python-renonce-a-une-subvention-de-15-million-de-dollars-plutot-qua-ses-valeurs-484243.htm</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140843/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/wilk/liens/la-fondation-python-renonce-a-une-subvention-plutot-qu-a-ses-valeurs-dei#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>wilk</name>
        </author>
    </entry>
    <entry>
        <title>Le renouveau de txt2tags?</title>
        <link href="https://linuxfr.org/users/zurvan-0/journaux/le-renouveau-de-txt2tags" />
        <id>https://linuxfr.org/users/zurvan-0/journaux/le-renouveau-de-txt2tags</id>
        <updated>2025-10-30T17:32:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, voici quelques nouvelles concernant txt2tags.</p>
<p><strong>Avertissement</strong></p>
<p>Je ne fais plus partie de l'équipe txt2tags sur github (<a href="https://github.com/txt2tags">https://github.com/txt2tags</a>), cette communication n'est donc pas <strong>officielle</strong>.</p>
<hr/>
<p>Txt2tags a été initialement développé par Aurelio Jargas, et d'autres personnes ont contribué au projet (moi y compris, à mon niveau), l'améliorant et le rendant de plus en plus épatant.</p>
<p>L'état actuel de txt2tags est le suivant :</p>
<ul>
<li><p>La version python2 est obsolète car python2 n'est plus fourni avec la plupart des distributions Linux.</p></li>
<li><p>La version python3 a supprimé presque toutes les fonctionnalités utiles (%%toc, %%date, système de "templates", nombreuses cibles) afin de le « simplifier ». Vous pouvez consulter un tableau des différences sur <a href="https://github.com/txt2tags/txt2tags">https://github.com/txt2tags/txt2tags</a></p></li>
</ul>
<p>Par ailleurs il semble que beaucoup de gens ont cessé d'utiliser txt2tags à cette époque, à la fin des années 2010. Déjà que c'était marginal, mais depuis quelques années c'est silence radio un peu partout. Je ne sais pas si cela est lié, mais il est certain que l'outil est devenu quoi qu'il en soit moins attractif avec ses fonctionnalités réduites.</p>
<p>Markdown n'est pas vraiment passionnant, d'autant plus qu'il manque de nombreuses fonctionnalités de base telles que la possibilité d'écrire (facilement) un commentaire ou d'utiliser des expressions régulières pour modifier des documents.</p>
<p>Pourtant, quelqu'un avait porté le code initial de python2 vers python3. Je l'ai maintenu, péniblement, jusqu'à présent, afin qu'il fonctionne même avec python 3.12.</p>
<p>Je l'ai inclus dans mon propre projet textallion :<br/>
<a href="https://github.com/farvardin/textallion/blob/master/contrib/txt2tags/txt2tags3">https://github.com/farvardin/textallion/blob/master/contrib/txt2tags/txt2tags3</a></p>
<p>J'utilise txt2tags presque tous les jours, que ce soit pour travailler sur des sites web ou pour rédiger des documents (livres, lettres, documentations…). Sa polyvalence et ses possibilités ne cessent de m'émerveiller :)</p>
<p>Je me demande si d'autres personnes l'utilisent encore tout comme moi.</p>
<p>Je n'aime pas l'idée de « détourner » le nom txt2tags en publiant un produit portant le même nom mais avec des fonctionnalités différentes (même s'il s'agit des fonctionnalités de base originales de la version Python 2). </p>
<p>Je me demande même s'il vaut la peine de le forker avec un nom différent et une équipe différente.</p>
<p>Qu'en pensez-vous ?</p>
<p>J'ai par ailleurs créé une nouvelle communauté sur reddit (il y avait avant une page facebook à <a href="https://www.facebook.com/txt2tags/">https://www.facebook.com/txt2tags/</a> mais c'est vraiment saturé de publicités, et d'ailleurs la plupart des publications sont cachées, n'atteignant peut-être que 10 % des abonnés actuels…)</p>
<p><a href="https://www.reddit.com/r/txt2tags/">https://www.reddit.com/r/txt2tags/</a> </p>
<p>Mais sinon c'est bien (voire mieux), d'en discuter sur linuxfr !</p>
<div><a href="https://linuxfr.org/users/zurvan-0/journaux/le-renouveau-de-txt2tags.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140822/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/zurvan-0/journaux/le-renouveau-de-txt2tags#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>zurvan</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115462602767924950" />
        <id>https://mamot.fr/@AFPy/115462602767924950</id>
        <updated>2025-10-30T10:18:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Stand d'accueil pour la PyConFR
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Offre d&#39;emploi CDI - Tech Lead pour la CNAM - Paris ou Lyon</title>
        <link href="https://discuss.afpy.org/t/offre-demploi-cdi-tech-lead-pour-la-cnam-paris-ou-lyon/2822" />
        <id>https://discuss.afpy.org/t/offre-demploi-cdi-tech-lead-pour-la-cnam-paris-ou-lyon/2822</id>
        <updated>2025-10-29T21:21:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Mon employeur, la Cnam (Caisse Nationale d’Assurance Maladie) recherche des personnes pour un poste de Tech Lead Python. J’ai pensé à la communauté AFPY.</p>
<p>Pour postuler ou consulter l’offre, voici le lien : <a class="inline-onebox" href="https://cnam-recrute.talent-soft.com/offre-de-emploi/emploi-tech-lead-python-_5753.aspx" rel="noopener nofollow ugc">Cnam - Tech Lead Python</a></p>
<p>Bonne soirée !</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/offre-demploi-cdi-tech-lead-pour-la-cnam-paris-ou-lyon/2822">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>FusionNucleaire</name>
        </author>
    </entry>
    <entry>
        <title>wx.python page web</title>
        <link href="https://discuss.afpy.org/t/wx-python-page-web/2820" />
        <id>https://discuss.afpy.org/t/wx-python-page-web/2820</id>
        <updated>2025-10-29T08:27:27Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>bonjour à tou[te]s</p>
<p>”simple” d’afficher une chaîne tv avec wx.python et wx.html2</p>
<p>exemple :</p>
<p><code>import wx,wx.html2</code><br/>
<code>class frm(wx.Frame):</code><br/>
<code>def</code><strong><code>init</code></strong><code>(self, url):</code><br/>
<code>  wx.Frame.</code><strong><code>init</code></strong><code>(self,None,wx.ID_ANY,“Affichage HTML distant”)</code><br/>
<code>  self.wv=wx.html2.WebView.New(self)</code><br/>
<code>  self.wv.LoadURL(url)</code><br/>
<code>  self.Show()</code><br/>
<code>app=wx.App(False)</code><br/>
<code>frame=frm(“``https://www.publicsenat.fr/direct”``)</code><br/>
<code>app.MainLoop()</code></p>
<p>y-a-il moyen de “récupérer” le flux<br/>
et de l’enregistrer dans un fichier ?</p>
<p>merci d’avance</p>
<p><small>13 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/wx-python-page-web/2820">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>bul3</name>
        </author>
    </entry>
    <entry>
        <title>Recherche mission python Freelance</title>
        <link href="https://discuss.afpy.org/t/recherche-mission-python-freelance/2818" />
        <id>https://discuss.afpy.org/t/recherche-mission-python-freelance/2818</id>
        <updated>2025-10-28T10:48:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Je suis en recherche d’une nouvelle mission en tant que freelance python dans le domaine du web.</p>
<p>J’ai déjà travaillé sur une application from scratch en <strong>Django</strong> et récemment sur un micro-service <strong>FastApi</strong> à forte charge en full <strong>asynchrone</strong>.</p>
<p><img alt=":technologist:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/technologist.png?v=15" title=":technologist:" width="20"/> Dev depuis 18 ans<br/>
<img alt=":classical_building:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/classical_building.png?v=15" title=":classical_building:" width="20"/> Remote / Lyon / Paris<br/>
<img alt=":oncoming_automobile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/oncoming_automobile.png?v=15" title=":oncoming_automobile:" width="20"/> 2 jours présentiel max / sem<br/>
<img alt=":hourglass_flowing_sand:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/hourglass_flowing_sand.png?v=15" title=":hourglass_flowing_sand:" width="20"/> Dispo ASAP<br/>
<img alt=":link:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/link.png?v=15" title=":link:" width="20"/> <a href="https://www.linkedin.com/in/davidrigaudie/" rel="noopener nofollow ugc">Profil LinkedIn</a></p>
<p>Pourquoi je suis la bonne personne :</p>
<ul>
<li>Je m’adapte à votre stack / process</li>
<li>Je suggère des améliorations au vu de mes expériences</li>
<li>Je maitrise tous les aspects web (API, sécu, déploiement…)</li>
<li>Je produis du code de qualité et testé</li>
<li>J’aime collaborer pour que l’équipe avance</li>
</ul>
<p>Vous avez un projet, parlons en dès maintenant =&gt; Via <a href="https://www.linkedin.com/in/davidrigaudie/" rel="noopener nofollow ugc">LinkedIn</a> ou <a href="https://calendly.com/itarverne/15min?month=2025-10" rel="noopener nofollow ugc">Calendly</a></p>
<p>Merci pour votre soutien</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/recherche-mission-python-freelance/2818">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>drigaudie</name>
        </author>
    </entry>
    <entry>
        <title>[Fondation Ptyhon] The PSF has withdrawn a $1.5 million proposal to US government grant program</title>
        <link href="https://linuxfr.org/users/ysabeau/liens/fondation-ptyhon-the-psf-has-withdrawn-a-1-5-million-proposal-to-us-government-grant-program" />
        <id>https://linuxfr.org/users/ysabeau/liens/fondation-ptyhon-the-psf-has-withdrawn-a-1-5-million-proposal-to-us-government-grant-program</id>
        <updated>2025-10-27T19:22:19Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://pyfound.blogspot.com/2025/10/NSF-funding-statement.html">https://pyfound.blogspot.com/2025/10/NSF-funding-statement.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140784/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/ysabeau/liens/fondation-ptyhon-the-psf-has-withdrawn-a-1-5-million-proposal-to-us-government-grant-program#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Ysabeau  🧶</name>
        </author>
    </entry>
    <entry>
        <title>[Fondation Python] The PSF has withdrawn a $1.5 million proposal to US government grant program</title>
        <link href="https://linuxfr.org/users/ysabeau/liens/fondation-python-the-psf-has-withdrawn-a-1-5-million-proposal-to-us-government-grant-program" />
        <id>https://linuxfr.org/users/ysabeau/liens/fondation-python-the-psf-has-withdrawn-a-1-5-million-proposal-to-us-government-grant-program</id>
        <updated>2025-10-27T19:22:19Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://pyfound.blogspot.com/2025/10/NSF-funding-statement.html">https://pyfound.blogspot.com/2025/10/NSF-funding-statement.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140784/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/ysabeau/liens/fondation-python-the-psf-has-withdrawn-a-1-5-million-proposal-to-us-government-grant-program#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Ysabeau  🧶</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115429633772681851" />
        <id>https://mamot.fr/@AFPy/115429633772681851</id>
        <updated>2025-10-24T15:33:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Call for volunteers for PyConFR 2025, taking place in Lyon at the René Cassin Campus from October 30 to November 2, 2025.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115429630221793588" />
        <id>https://mamot.fr/@AFPy/115429630221793588</id>
        <updated>2025-10-24T15:32:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Appel à volontaires pour la PyConFR 2025 se déroulant à Lyon au Campus René Cassin, du 30 octobre au 02 novembre 2025
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>De l&#39;ancien monde ... Génération d&#39;index pour publications scientifiques/littéraire</title>
        <link href="https://linuxfr.org/users/caeies/journaux/de-l-ancien-monde-generation-d-index-pour-publications-scientifiques-litteraire" />
        <id>https://linuxfr.org/users/caeies/journaux/de-l-ancien-monde-generation-d-index-pour-publications-scientifiques-litteraire</id>
        <updated>2025-10-18T15:06:54Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à toute la communauté!</p>
<p>&lt;mavie&gt;<br/>
Je suis un informaticien, compagnon d'une universitaire qui est en train de publier avec des collègues une somme sur un auteur ancien.<br/>
&lt;/mavie&gt;</p>
<p>Je voudrais l'aider à générer les références de l'index de l'ouvrage. Ça représente un certain volume de texte (on parle de 6 volumes d'environ 1000 pages chacun), et l'index contient environ 3400 entrées …</p>
<p>Bien entendu, ce sont des littéraires, la mise en page finale est en cours et je n'ai que les pdf des tirages finaux pour composer les liens (oui ça aurait été bien plus facile avec du latex et les balises \index mais la moyenne d'âge des co-éditeurs frise les 65 ans).</p>
<p>Je me dis que ce problème à du être rencontré un peu partout dans le monde universitaire et peut être que je suis passé à côté d'un projet Européen ou autre qui pourrait nous aider à faire ça "plus facilement".</p>
<p>J'ai commencé quelque chose de mon côté, avec l'aide des IAs (je me dis que c'est un bon projet perso pour confirmer ce que je pense (ou pas) du code construit par les IA (ça fera l'objet d'un autre journal si j'aboutis à quelque chose)).</p>
<p>Le principe serait de permettre la description de l'index via une interface web (plus simple pour des néophytes ?), puis la génération du document d'index final.</p>
<p>Je pensais que ça serait simple, mais en fait c'est bien plus complexe que ce qu'il n'y parait. Par exemple comment trouver les noms des gens présents dans l'index, lorsque deux noms de famille identiques sont présents, comment gérer les références dans l'index (les "see also"), comment gérer les titres sur de la concordance (matching) multi-ligne, etc … Sans compter le côté humain de l'index actuel (comprendre avec des erreurs, le formatage est un peu aléatoire, etc …)</p>
<p>Bref c'est une tâche bien plus importante que mon idée de départ, alors je fais appel à ceux qui savent / ont déjà fait ça : comment avez-vous fait ?</p>
<p>(la réponse "c'est l'éditeur qui a pris ça en charge me va", mais dans leur cas, c'est niet, les universités de Princenton leurs ont dit débrouillez-vous).</p>
<p>Merci d'avance pour vos idées !</p>
<p>Caeies</p>
<div><a href="https://linuxfr.org/users/caeies/journaux/de-l-ancien-monde-generation-d-index-pour-publications-scientifiques-litteraire.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140680/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/caeies/journaux/de-l-ancien-monde-generation-d-index-pour-publications-scientifiques-litteraire#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Caeies</name>
        </author>
    </entry>
    <entry>
        <title>Qu’est-ce que Podman : principes et architecture</title>
        <link href="https://bearstech.com/societe/blog/quest-ce-que-podman-principes-et-architecture" />
        <id>https://bearstech.com/societe/blog/quest-ce-que-podman-principes-et-architecture</id>
        <updated>2025-10-16T13:45:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115372491197039741" />
        <id>https://mamot.fr/@AFPy/115372491197039741</id>
        <updated>2025-10-14T13:21:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Reservations for the Saturday, November 1 evening event for PyConFR 2025 close on October 19, 2025.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115372485703076537" />
        <id>https://mamot.fr/@AFPy/115372485703076537</id>
        <updated>2025-10-14T13:20:22Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Fin des réservations pour la soirée du samedi 1er Novembre pour la PyConFR 2025 au 19 Octobre 2025
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Django : un ORM pour toutes les bases de données</title>
        <link href="https://www.paulox.net/2025/10/06/django-orm-comparison/" />
        <id>https://www.paulox.net/2025/10/06/django-orm-comparison/</id>
        <updated>2025-10-13T11:03:58Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez une analyse comparative approfondie des différents backends de bases de données officiellement supportés par l’ORM de Django. Cet article vous permet d’économiser du temps en explorant les spécificités, les forces et les limites de chaque implémentation, vous aidant à faire les meilleurs choix techniques pour vos projets Django.</p>
<a href="https://news.humancoders.com/t/python/items/39336-django-un-orm-pour-toutes-les-bases-de-donnees"><img src="https://www.paulox.net/images/PXL_20250910_232244553.webp"/></a><hr/><a href="https://news.humancoders.com/t/python/items/39336-django-un-orm-pour-toutes-les-bases-de-donnees#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/39336-django-un-orm-pour-toutes-les-bases-de-donnees">Django : un ORM pour toutes les bases de données</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 22 octobre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-22-octobre/2804" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-22-octobre/2804</id>
        <updated>2025-10-13T09:17:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Pour ce meetup d’octobre, on se retrouve le mercredi 22 octobre à 19h, dans les locaux de Wanadev (métro Gare de Vaise).</p>
<p>Ce mois-ci, le meetup se fait avec le groupe PostgreSQL ! On a donc deux présentations au programme :</p>
<ul>
<li>de la programmation par contraintes en Python, par <a class="mention" href="https://discuss.afpy.org/u/matthieusb">@matthieusb</a></li>
<li>de l’utilisation (ou non) d’ORM, par Pierre-Henri</li>
</ul>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-22-octobre/2804/1">Rencontre PostgreSQL x Python</a></p>
<p>2025-10-22 19:00 (Europe/Paris) → 2025-10-22 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-22-octobre/2804">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>C⛧omplete List of Official Coinbase™ TOLL FREE™ Contact Numbers in the usa : Detailed StepbyStep Guide</title>
        <link href="https://discuss.afpy.org/t/c-omplete-list-of-official-coinbase-toll-free-contact-numbers-in-the-usa-detailed-stepbystep-guide/2801" />
        <id>https://discuss.afpy.org/t/c-omplete-list-of-official-coinbase-toll-free-contact-numbers-in-the-usa-detailed-stepbystep-guide/2801</id>
        <updated>2025-10-12T17:29:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), In the fast-paced world of [c.r.y.pt]…[o.cu.rre.nc].y, having access to reliable customer service is essential. Coinbase, one of the most popular and widely used crypto exchanges globally, serves millions of users looking to buy, sell, store, or trade digital currencies. While the platform is known for its secure and user-friendly experience, users may still encounter technical issues, account access problems, or security concerns. If you’re searching for the Coinbase customer service number, Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), you’re not alone. Many users want a direct way to reach a real person when something goes wrong. Here’s everything you need to know about contacting Coinbase USA Support, especially by phone.</p>
<p>*** Coinbase customer service number 820 229 4746</p>
<p>*** Coinbase phone number customer service 820 229 4746</p>
<p>*** Coinbase 24/7 customer service number 820 229 4746</p>
<p>*** Coinbase customer USA Support phone number 820 229 4746</p>
<p>*** Coinbase help line number 820 229 4746</p>
<p>*** Coinbase customer care contact 820 229 4746</p>
<p>*** Coinbase service number 820 229 4746</p>
<p>*** Coinbase toll-free customer service 820 229 4746</p>
<p>*** Coinbase contact number for USA Support 820 229 4746</p>
<p>*** Coinbase account service number820 229 4746</p>
<p>*** Coinbase number for customer help 820 229 4746</p>
<p>*** Coinbase service hotline 820 229 4746</p>
<p>*** Coinbase live customer service 820 229 4746</p>
<p>*** Coinbase technical help number 820 229 4746</p>
<p>*** Coinbase customer assistance number 820 229 4746</p>
<p>*** Coinbase login issue contact 820 229 4746</p>
<p>*** Coinbase customer service chat number 820 229 4746</p>
<p>*** Coinbase complaint phone number 820 229 4746</p>
<p>*** Coinbase verification help line 820 229 4746</p>
<p>*** Coinbase fraud prevention number 820 229 4746</p>
<p>*** Does Coinbase Have a Customer Service Number? <em>820 229 4746</em></p>
<p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), Yes, Coinbase does provide customer service via phone for certain issues. The official Coinbase customer service number in the United States is:</p>
<p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (),</p>
<p>This number is available 24/7 and is mainly intended for account-related issues such as:</p>
<p>Account access problems 1- 820 ⊹229⟶ 4746</p>
<p>Reporting unauthorized activity 1- 820 ⊹229⟶ 4746</p>
<p>Suspicious login attempts 1- 820 ⊹229⟶ 4746</p>
<p>Compromised or hacked accounts 1- 820 ⊹229⟶ 4746</p>
<p>It’s important to note that Coinbase.] 1- 820 ⊹229⟶ 4746 USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), Coinbase will not ask you for your password, PIN, or two-step verification code over the phone 1- 820 ⊹229⟶ 4746. They also do not allow you to make transactions or manage your crypto via customer service phone calls.</p>
<p>What Types of USA Support Are Available by Phone?</p>
<p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), The Coinbase phone USA Support line is designed primarily to handle urgent security issues. 1- 820 ⊹229⟶ 4746 For example, if you suspect your account has been compromised or you’re locked out and unable to log in, the phone USA Support team can help guide you through the recovery process. 1- 820 ⊹229⟶ 4746 However, routine inquiries—like questions about trading, delays in withdrawals, payment methods, or general account settings—are usually handled through other channels.</p>
<p>Alternative Ways to Get Help from Coinbase 1- 820 ⊹229⟶ 4746</p>
<p>Or 1- 820 ⊹229⟶ 4746 If your issue isn’t urgent, Coinbase provides a number 820 ⊹229⟶ 4746 of other helpful USA Support options:</p>
<p>Help Center</p>
<p>The Coinbase Help Center number 820 ⊹229⟶ 4746 hundreds of USA Support articles on everything from basic account setup to complex transaction troubleshooting.</p>
<p>Submit a Request</p>
<p>Users can log in to their Coinbase USA Support 820 ⊹229⟶ 4746 and submit a ticket for non-urgent issues. USA Support will respond via email.</p>
<p>Live Chat</p>
<p>Available through the website or Coinbase USA Support 820 ⊹229⟶ 4746 , live chat is a convenient way to speak to an agent in real time for common concerns.</p>
<p>Social Media USA Support</p>
<p>The official Coinbase Twitter USA Support handle, CoinbaseUSA Support 820 ⊹229⟶ 4746 , provides updates and helps users with general issues. Avoid sharing personal info in public threads.</p>
<p>Beware of Scams</p>
<p>Many fake websites and phone numbers 820 ⊹229⟶ 4746 claim to be Coinbase USA Support 820 ⊹229⟶ 4746 . These scams attempt</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/c-omplete-list-of-official-coinbase-toll-free-contact-numbers-in-the-usa-detailed-stepbystep-guide/2801">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>sdcsdfc</name>
        </author>
    </entry>
    <entry>
        <title>C⛧omplete List of Official Coinbase™️ WALLET SUPPORT ™️ Contact Numbers in the usa : Detailed StepbyStep Guide</title>
        <link href="https://discuss.afpy.org/t/c-omplete-list-of-official-coinbase-wallet-support-contact-numbers-in-the-usa-detailed-stepbystep-guide/2800" />
        <id>https://discuss.afpy.org/t/c-omplete-list-of-official-coinbase-wallet-support-contact-numbers-in-the-usa-detailed-stepbystep-guide/2800</id>
        <updated>2025-10-12T17:18:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), In the fast-paced world of [c.r.y.pt]…[o.cu.rre.nc].y, having access to reliable customer service is essential. Coinbase, one of the most popular and widely used crypto exchanges globally, serves millions of users looking to buy, sell, store, or trade digital currencies. While the platform is known for its secure and user-friendly experience, users may still encounter technical issues, account access problems, or security concerns. If you’re searching for the Coinbase customer service number, Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), you’re not alone. Many users want a direct way to reach a real person when something goes wrong. Here’s everything you need to know about contacting Coinbase USA Support, especially by phone.</p>
<p>*** Coinbase customer service number 820 229 4746</p>
<p>*** Coinbase phone number customer service 820 229 4746</p>
<p>*** Coinbase 24/7 customer service number 820 229 4746</p>
<p>*** Coinbase customer USA Support phone number 820 229 4746</p>
<p>*** Coinbase help line number 820 229 4746</p>
<p>*** Coinbase customer care contact 820 229 4746</p>
<p>*** Coinbase service number 820 229 4746</p>
<p>*** Coinbase toll-free customer service 820 229 4746</p>
<p>*** Coinbase contact number for USA Support 820 229 4746</p>
<p>*** Coinbase account service number820 229 4746</p>
<p>*** Coinbase number for customer help 820 229 4746</p>
<p>*** Coinbase service hotline 820 229 4746</p>
<p>*** Coinbase live customer service 820 229 4746</p>
<p>*** Coinbase technical help number 820 229 4746</p>
<p>*** Coinbase customer assistance number 820 229 4746</p>
<p>*** Coinbase login issue contact 820 229 4746</p>
<p>*** Coinbase customer service chat number 820 229 4746</p>
<p>*** Coinbase complaint phone number 820 229 4746</p>
<p>*** Coinbase verification help line 820 229 4746</p>
<p>*** Coinbase fraud prevention number 820 229 4746</p>
<p>*** Does Coinbase Have a Customer Service Number? <em>820 229 4746</em></p>
<p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), Yes, Coinbase does provide customer service via phone for certain issues. The official Coinbase customer service number in the United States is:</p>
<p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (),</p>
<p>This number is available 24/7 and is mainly intended for account-related issues such as:</p>
<p>Account access problems 1- 820 ⊹229⟶ 4746</p>
<p>Reporting unauthorized activity 1- 820 ⊹229⟶ 4746</p>
<p>Suspicious login attempts 1- 820 ⊹229⟶ 4746</p>
<p>Compromised or hacked accounts 1- 820 ⊹229⟶ 4746</p>
<p>It’s important to note that Coinbase.] 1- 820 ⊹229⟶ 4746 USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), Coinbase will not ask you for your password, PIN, or two-step verification code over the phone 1- 820 ⊹229⟶ 4746. They also do not allow you to make transactions or manage your crypto via customer service phone calls.</p>
<p>What Types of USA Support Are Available by Phone?</p>
<p>Coinbase.] USA Support®ï¸ Contact Numbers is ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 or ⇠⟦+1⟧⇢ ⊹ 820⊹229⟶4746 (), The Coinbase phone USA Support line is designed primarily to handle urgent security issues. 1- 820 ⊹229⟶ 4746 For example, if you suspect your account has been compromised or you’re locked out and unable to log in, the phone USA Support team can help guide you through the recovery process. 1- 820 ⊹229⟶ 4746 However, routine inquiries—like questions about trading, delays in withdrawals, payment methods, or general account settings—are usually handled through other channels.</p>
<p>Alternative Ways to Get Help from Coinbase 1- 820 ⊹229⟶ 4746</p>
<p>Or 1- 820 ⊹229⟶ 4746 If your issue isn’t urgent, Coinbase provides a number 820 ⊹229⟶ 4746 of other helpful USA Support options:</p>
<p>Help Center</p>
<p>The Coinbase Help Center number 820 ⊹229⟶ 4746 hundreds of USA Support articles on everything from basic account setup to complex transaction troubleshooting.</p>
<p>Submit a Request</p>
<p>Users can log in to their Coinbase USA Support 820 ⊹229⟶ 4746 and submit a ticket for non-urgent issues. USA Support will respond via email.</p>
<p>Live Chat</p>
<p>Available through the website or Coinbase USA Support 820 ⊹229⟶ 4746 , live chat is a convenient way to speak to an agent in real time for common concerns.</p>
<p>Social Media USA Support</p>
<p>The official Coinbase Twitter USA Support handle, CoinbaseUSA Support 820 ⊹229⟶ 4746 , provides updates and helps users with general issues. Avoid sharing personal info in public threads.</p>
<p>Beware of Scams</p>
<p>Many fake websites and phone numbers 820 ⊹229⟶ 4746 claim to be Coinbase USA Support 820 ⊹229⟶ 4746 . These scams attempt</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/c-omplete-list-of-official-coinbase-wallet-support-contact-numbers-in-the-usa-detailed-stepbystep-guide/2800">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>sdcsdfc</name>
        </author>
    </entry>
    <entry>
        <title>Confirm {List} of ✈United Customer® Contact Numbers in US : A Complete step by step Guide</title>
        <link href="https://discuss.afpy.org/t/confirm-list-of-united-customer-contact-numbers-in-us-a-complete-step-by-step-guide/2799" />
        <id>https://discuss.afpy.org/t/confirm-list-of-united-customer-contact-numbers-in-us-a-complete-step-by-step-guide/2799</id>
        <updated>2025-10-12T17:06:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Learn how to file a complaint with United airlines ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ for various issues, such as delayed or cancelled flights, denied boarding, baggage problems, and more. United airlines main customer service number is 1-800-United airlines + ║ +║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) )) (Live Person), where you can reach a live representative 24/7.║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) ║ Whet her you’re dealing with booking changes, flight cancellations, or have questions regarding refunds or compensation, speaking to a live person ensures prompt resolution. ║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) ║You can also reach out via United airlines ’s live chat feature or email support for assistance. For all your inquiries, call + ║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) (Live Person). This guide explains + ║ + ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ how to contact United airlines customer service effectively, along with tips for minimizing wait times. To speak to a live representative, dial + ║ + ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ or + ║ + ║+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) (Live Person).<br/>
Why Contact a Live Person in United airlines ?<br/>
There are many reasons why speaking to a live person might be the best route to resolving your issue. United airlines scenarios include: Flight changes or cancellations: If your plans have changed, you need live assistance at United airlines + ║ +║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ ║★ ║ (Live Person) with adjusting or canceling your flights, or you’re dealing with flight cancellations and delays.<br/>
Booking clarification: Sometimes you need more details or help to understand the specifics of your United airlines booking + ║ +║‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ (Live Person) and reservation. Refunds and compensation: Automated systems cannot often handle complex refund requests or compensation claims, making &amp; United airlines live agent+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) (Live Person) invaluable.<br/>
Technical glitches: If there’s a technical issue with your booking, like payment errors, United airlines live customer service + ║ + ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ or + ║ + ║+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) (Live Person) can resolve it quickly.<br/>
United airlines ’s Contact Options United airlines offers + ║ +║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ (Live Person) several ways to get in touch with their customer service, whether you prefer calling, chatting, or reaching out on social media.<br/>
Calling United airlines ’s Customer Service Hotline<br/>
The most straightforward way to talk to a live person is by calling ║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) ║their customer service hotline. United airlines 's main customer service number is 1-800-United airlines + ║ +║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ + ║ + ║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) )) (Live Person) or + ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║ or + ║ + ║+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) (Live Person). When you call║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) ║, you’ll be prompted to select options that direct you to the appropriate department, but be patient—there is always a way to reach a live person. Using United airlines ’s Live Chat Feature<br/>
If waiting on hold isn’t your style, you can use United airlines ’s live chat feature║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕)) ⊹║)) ║. Simply head over to their website, navigate to the Help section, and select the chat option║((║‬‬‬‬‬‬‬‬1-800-804—45-97)) ⊹║)) ║. This connects you with a real person who can assist you just as well as phone support can.<br/>
Step-by-Step: Talking to a Live Person via Phone‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬ +𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕<br/>
If you’re calling from outside the US‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬ +𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕, here are some useful numbers:<br/>
United airlines Australia:<br/>
United airlines Customer Service Queries<br/>
People Also Search:<br/>
Call To Live Agent At United airlines<br/>
Contact a live agent at United airlines .<br/>
Speak to a live agent at United airlines .<br/>
Talk to a live agent at United airlines ®<br/>
When travel plans United airlines ©© ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕║ made through United airlines ©©® get disrupted or last-minute updates are needed, reaching a live agent at +𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕║ ║ becomes the most efficient solution. Whether it’s flight rescheduling, hotel coordination, or lost itinerary confirmation, calling +𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬++𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕║ ║ connects you to a real United airlines ©©® support representative who can resolve the issue immediately.<br/>
speaking to a live agent at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║+1—𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ allows you to clearly explain your situation and receive tailored support. This approach is especially useful in complex cases like itinerary errors, failed refunds, and unexpected flight cancellations where self-service tools fall short. Front-line advisors at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ can view your full booking details and take immediate action on your behalf.<br/>
Why Speak With a Live United airlines ©©® Agent?<br/>
A trained live adviser at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ can access real-time inventory and backend tools, allowing them to confirm policy exceptions and make changes that an automated menu may block. Common service cases include unexpected delays, technical billing errors, and lost email confirmations, all of which are better resolved by directly calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║.<br/>
In many situations, travelers are unable to log in or view updated flight information. In such cases, reaching customer service at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ becomes the most reliable method to retrieve accurate travel details or request immediate modifications.<br/>
Official United airlines ©©® USA Customer Service Number +𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕<br/>
The main to-ll-free United airlines ©©® U.S. number is ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║, available 24 hours per day. Passengers throughout the USA can use this line to connect with support agents who handle flight changes, hotel issues, package trips, and travel protection inquiries. Keep ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ saved on your mobile phone for immediate help during your travels.<br/>
Step-by-Step: How to Connect With a Real United airlines ©©® Representative<br/>
To speak with a live person, dial ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║. When the automated voice system begins, select “Existing Booking” and wait for the next prompt. If you do not hear a direct option, press “0” or clearly say “live agent,” and the system will route you to an United airlines ©©® advisor at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║.<br/>
Tip: call early in the morning or late in the evening to reach ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ faster and avoid peak wait times.<br/>
Complete List of United airlines ©©® Contact Options<br/>
Method<br/>
How to Access<br/>
Phone Hotline<br/>
‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║<br/>
Live Chat<br/>
Go to the Help Center → click “Chat”<br/>
Mobile App<br/>
Open United airlines ©©® App → My Trips → Help<br/>
Email Support<br/>
Submit contact form in the Help Center<br/>
Social Media<br/>
Message United airlines ©©® on Twitter / Facebook<br/>
For the fastest support, always start by calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ before using chat or email.<br/>
International United airlines ©©® Support Numbers<br/>
Although this guide primarily covers the USA support line ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║, international travelers can also receive support by calling the same number from abroad. In France, the number remains ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║, while U.K and Australia users may be directed to their regional centers after dialing ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ and choosing their country option in the automated menu.<br/>
For Spanish-speaking travelers who need help with United airlines ©©® reservations, the fastest way is still to dial ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ and select “Español” when prompted.<br/>
Common Issues Solved by United airlines ©©® Live Agents<br/>
Travelers regularly call ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ for assistance with flight rebookings, refund requests, or hotel reservation conflicts. United airlines ©©® agents also support duplicate charges, reactivation of canceled itineraries, and clarification of complicated booking terms. For any unexpected situation, the fastest way to get a resolution remains calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║.<br/>
Refund Policy Overview<br/>
If you need to request a refund for a canceled flight or unused hotel booking, contact ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║. Refund eligibility varies based on airline and hotel policies; however, United airlines ©©® agents can manually submit claims, track progress, and escalate unresolved cases. Always call ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ if your online request hasn’t received a response within 72 hours.<br/>
Frequently Asked Questions (FAQ)<br/>
Q: Can I bypass United airlines ©©®’s automated phone menus?<br/>
A: Yes. Dial +𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║, press 0, or say “agent” until you get transferred.<br/>
Q: Is a booking number required when contacting United airlines ©©®?<br/>
A: It helps speed up the process, but ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ agents can verify you using your email or phone number as well.<br/>
Q: What is the fastest way to reach support?<br/>
A: Calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ directly (during early morning hours) is usually the quickest option.<br/>
For any urgent changes, always contact ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+𝟖𝟎𝟎-𝟖𝟎𝟒-𝟒𝟓𝟗𝟕 ║ ║ first — United airlines ©©® live agents are available 24/7 and can solve even the most complex travel issues quickly and professionally.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/confirm-list-of-united-customer-contact-numbers-in-us-a-complete-step-by-step-guide/2799">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>kimberlyn</name>
        </author>
    </entry>
    <entry>
        <title>Confirm {List} of Delta Customer® Contact Numbers in US : A Complete step by step Guide</title>
        <link href="https://discuss.afpy.org/t/confirm-list-of-delta-customer-contact-numbers-in-us-a-complete-step-by-step-guide/2798" />
        <id>https://discuss.afpy.org/t/confirm-list-of-delta-customer-contact-numbers-in-us-a-complete-step-by-step-guide/2798</id>
        <updated>2025-10-12T17:01:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Learn how to file a complaint with Delta airlines ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║ for various issues, such as delayed or cancelled flights, denied boarding, baggage problems, and more. Delta airlines main customer service number is 1-800-Delta airlines + ║ +║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║)) )) (Live Person), where you can reach a live representative 24/7.║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) ║ Whet her you’re dealing with booking changes, flight cancellations, or have questions regarding refunds or compensation, speaking to a live person ensures prompt resolution. ║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) ║You can also reach out via Delta airlines ’s live chat feature or email support for assistance. For all your inquiries, call + ║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║)) (Live Person). This guide explains + ║ + ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║ how to contact Delta airlines customer service effectively, along with tips for minimizing wait times. To speak to a live representative, dial + ║ + ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║ or + ║ + ║+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) (Live Person).<br/>
Why Contact a Live Person in Delta airlines ?<br/>
There are many reasons why speaking to a live person might be the best route to resolving your issue. Delta airlines scenarios include: Flight changes or cancellations: If your plans have changed, you need live assistance at Delta airlines + ║ +║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ ║★ ║ (Live Person) with adjusting or canceling your flights, or you’re dealing with flight cancellations and delays.<br/>
Booking clarification: Sometimes you need more details or help to understand the specifics of your Delta airlines booking + ║ +║‬‬‬‬‬‬‬‬+1—800—804—45-97)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ (Live Person) and reservation. Refunds and compensation: Automated systems cannot often handle complex refund requests or compensation claims, making &amp; Delta airlines live agent+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) (Live Person) invaluable.<br/>
Technical glitches: If there’s a technical issue with your booking, like payment errors, Delta airlines live customer service + ║ + ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║ or + ║ + ║+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) (Live Person) can resolve it quickly.<br/>
Delta airlines ’s Contact Options Delta airlines offers + ║ +║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ ++ ║ + ║((║‬‬‬‬‬‬‬‬1—800—804—45-97)) ⊹║ (Live Person) several ways to get in touch with their customer service, whether you prefer calling, chatting, or reaching out on social media.<br/>
Calling Delta airlines ’s Customer Service Hotline<br/>
The most straightforward way to talk to a live person is by calling ║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) ║their customer service hotline. Delta airlines 's main customer service number is 1-800-Delta airlines + ║ +║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║ + ║ + ║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) )) (Live Person) or + ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║ or + ║ + ║+║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) (Live Person). When you call║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) ║, you’ll be prompted to select options that direct you to the appropriate department, but be patient—there is always a way to reach a live person. Using Delta airlines ’s Live Chat Feature<br/>
If waiting on hold isn’t your style, you can use Delta airlines ’s live chat feature║((║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬1-800-804-4597)) ⊹║)) ║. Simply head over to their website, navigate to the Help section, and select the chat option║((║‬‬‬‬‬‬‬‬1-800-804—45-97)) ⊹║)) ║. This connects you with a real person who can assist you just as well as phone support can.<br/>
Step-by-Step: Talking to a Live Person via Phone‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬ +1—800—804—45-97<br/>
If you’re calling from outside the US‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬ +1—800—804—45-97, here are some useful numbers:<br/>
Delta airlines Australia:<br/>
Delta airlines Customer Service Queries<br/>
People Also Search:<br/>
Call To Live Agent At Delta airlines<br/>
Contact a live agent at Delta airlines .<br/>
Speak to a live agent at Delta airlines .<br/>
Talk to a live agent at Delta airlines ®<br/>
When travel plans Delta airlines ©© ║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97║ made through Delta airlines ©©® get disrupted or last-minute updates are needed, reaching a live agent at +1—800—804—45-97or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97║ ║ becomes the most efficient solution. Whether it’s flight rescheduling, hotel coordination, or lost itinerary confirmation, calling +1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬++1—800—804—45-97║ ║ connects you to a real Delta airlines ©©® support representative who can resolve the issue immediately.<br/>
speaking to a live agent at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║+1—800—804—45-97 ║ ║ allows you to clearly explain your situation and receive tailored support. This approach is especially useful in complex cases like itinerary errors, failed refunds, and unexpected flight cancellations where self-service tools fall short. Front-line advisors at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ can view your full booking details and take immediate action on your behalf.<br/>
Why Speak With a Live Delta airlines ©©® Agent?<br/>
A trained live adviser at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ can access real-time inventory and backend tools, allowing them to confirm policy exceptions and make changes that an automated menu may block. Common service cases include unexpected delays, technical billing errors, and lost email confirmations, all of which are better resolved by directly calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║.<br/>
In many situations, travelers are unable to log in or view updated flight information. In such cases, reaching customer service at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ becomes the most reliable method to retrieve accurate travel details or request immediate modifications.<br/>
Official Delta airlines ©©® USA Customer Service Number +1—800—804—45-97<br/>
The main to-ll-free Delta airlines ©©® U.S. number is ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║, available 24 hours per day. Passengers throughout the USA can use this line to connect with support agents who handle flight changes, hotel issues, package trips, and travel protection inquiries. Keep ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ saved on your mobile phone for immediate help during your travels.<br/>
Step-by-Step: How to Connect With a Real Delta airlines ©©® Representative<br/>
To speak with a live person, dial ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║. When the automated voice system begins, select “Existing Booking” and wait for the next prompt. If you do not hear a direct option, press “0” or clearly say “live agent,” and the system will route you to an Delta airlines ©©® advisor at ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║.<br/>
Tip: call early in the morning or late in the evening to reach ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ faster and avoid peak wait times.<br/>
Complete List of Delta airlines ©©® Contact Options<br/>
Method<br/>
How to Access<br/>
Phone Hotline<br/>
‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║<br/>
Live Chat<br/>
Go to the Help Center → click “Chat”<br/>
Mobile App<br/>
Open Delta airlines ©©® App → My Trips → Help<br/>
Email Support<br/>
Submit contact form in the Help Center<br/>
Social Media<br/>
Message Delta airlines ©©® on Twitter / Facebook<br/>
For the fastest support, always start by calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ before using chat or email.<br/>
International Delta airlines ©©® Support Numbers<br/>
Although this guide primarily covers the USA support line ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║, international travelers can also receive support by calling the same number from abroad. In France, the number remains ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║, while U.K and Australia users may be directed to their regional centers after dialing ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ and choosing their country option in the automated menu.<br/>
For Spanish-speaking travelers who need help with Delta airlines ©©® reservations, the fastest way is still to dial ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ and select “Español” when prompted.<br/>
Common Issues Solved by Delta airlines ©©® Live Agents<br/>
Travelers regularly call ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ for assistance with flight rebookings, refund requests, or hotel reservation conflicts. Delta airlines ©©® agents also support duplicate charges, reactivation of canceled itineraries, and clarification of complicated booking terms. For any unexpected situation, the fastest way to get a resolution remains calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║.<br/>
Refund Policy Overview<br/>
If you need to request a refund for a canceled flight or unused hotel booking, contact ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║. Refund eligibility varies based on airline and hotel policies; however, Delta airlines ©©® agents can manually submit claims, track progress, and escalate unresolved cases. Always call ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ if your online request hasn’t received a response within 72 hours.<br/>
Frequently Asked Questions (FAQ)<br/>
Q: Can I bypass Delta airlines ©©®’s automated phone menus?<br/>
A: Yes. Dial +1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║, press 0, or say “agent” until you get transferred.<br/>
Q: Is a booking number required when contacting Delta airlines ©©®?<br/>
A: It helps speed up the process, but ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ agents can verify you using your email or phone number as well.<br/>
Q: What is the fastest way to reach support?<br/>
A: Calling ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ directly (during early morning hours) is usually the quickest option.<br/>
For any urgent changes, always contact ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1—800—804—45-97 or ║║‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬+1-800-804-4597 ║ ║ first — Delta airlines ©©® live agents are available 24/7 and can solve even the most complex travel issues quickly and professionally.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/confirm-list-of-delta-customer-contact-numbers-in-us-a-complete-step-by-step-guide/2798">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>kimberlyn</name>
        </author>
    </entry>
    <entry>
        <title>Why it took 4 years to get a lock files specification</title>
        <link href="https://linuxfr.org/users/abarret/liens/why-it-took-4-years-to-get-a-lock-files-specification" />
        <id>https://linuxfr.org/users/abarret/liens/why-it-took-4-years-to-get-a-lock-files-specification</id>
        <updated>2025-10-12T16:25:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://snarky.ca/why-it-took-4-years-to-get-a-lock-files-specification/">https://snarky.ca/why-it-took-4-years-to-get-a-lock-files-specification/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140606/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/abarret/liens/why-it-took-4-years-to-get-a-lock-files-specification#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>vitanix</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Python 3.14</title>
        <link href="https://zestedesavoir.com/articles/4902/sortie-de-python-3-14/" />
        <id>https://zestedesavoir.com/articles/4902/sortie-de-python-3-14/</id>
        <updated>2025-10-12T14:22:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                π-thon
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Python 3.14</title>
        <link href="https://zestedesavoir.com/billets/4949/sortie-de-python-3-14-1/" />
        <id>https://zestedesavoir.com/billets/4949/sortie-de-python-3-14-1/</id>
        <updated>2025-10-10T12:37:40Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                π-thon
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Problème de type de données dans csv</title>
        <link href="https://discuss.afpy.org/t/probleme-de-type-de-donnees-dans-csv/2789" />
        <id>https://discuss.afpy.org/t/probleme-de-type-de-donnees-dans-csv/2789</id>
        <updated>2025-10-10T09:55:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>depuis peu je rencontre un problème de type de données quand je lis un fichier csv avec pandas.</p>
<p>Les données récupérées sont soit “‘donnée’” (guillemets doubles+simple) ou “donnée”, y compris pour les noms de colonnes, déclarées pourtant “nom_col”. Une piste ? Les données sont en UTF-8, délimiteur=virgule : du standard fait avec LibreOffice.</p>
<p>Merci</p>
<p><small>10 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-de-type-de-donnees-dans-csv/2789">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Covoiturage pour la PyconFR</title>
        <link href="https://discuss.afpy.org/t/covoiturage-pour-la-pyconfr/2786" />
        <id>https://discuss.afpy.org/t/covoiturage-pour-la-pyconfr/2786</id>
        <updated>2025-10-08T13:53:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello !</p>
<p>Nous allons nous rendre à Lyon en voiture depuis Paris, on voyage à 2 avec 2 petites chiennes et on a encore 2 places. Si certains veulent se joindre à nous on doit pouvoir s’arranger.</p>
<p>Nos dates de trajet :</p>
<p>Aller Mercredi 29/10 matinée - retour mardi 04/11 matinée</p>
<p>PS : si certain veulent proposer d’autre covoit’, n’hésitez pas à le faire ici <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=14" title=":slight_smile:" width="20"/></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/covoiturage-pour-la-pyconfr/2786">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Chadys</name>
        </author>
    </entry>
    <entry>
        <title>Sur Toulouse, des intéressés ?</title>
        <link href="https://discuss.afpy.org/t/sur-toulouse-des-interesses/2785" />
        <id>https://discuss.afpy.org/t/sur-toulouse-des-interesses/2785</id>
        <updated>2025-10-08T13:30:57Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous !</p>
<p>J’ai été contacté par une entreprise qui voudrait bien héberger des meetups chez elle dans la région de Toulouse. Le format serait accueil des participants et speakers, suivi d’un apéro networking convivial.</p>
<p>Si des personnes dans le coin serait intéressés pour lancer le mouvement, dite le moi ici ou en MP et je vous mets en contact !</p>
<p><small>4 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-toulouse-des-interesses/2785">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Chadys</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115332539532007715" />
        <id>https://mamot.fr/@AFPy/115332539532007715</id>
        <updated>2025-10-07T12:01:32Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Registration is now open (mandatory and free) for PyConFR 2025, taking place from October 30 to November 2, 2025.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115332511236597316" />
        <id>https://mamot.fr/@AFPy/115332511236597316</id>
        <updated>2025-10-07T11:54:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Inscription ouverte (obligatoire et gratuite) pour la PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115327641553857482" />
        <id>https://mamot.fr/@AFPy/115327641553857482</id>
        <updated>2025-10-06T15:15:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Assemblée Générale de l'AFPy le 2 Novembre 2025<br />Soyez à jour de vos cotisations (jusqu'au 19 octobre inclus)
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Crème CRM en version 2.7</title>
        <link href="https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-7" />
        <id>https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-7</id>
        <updated>2025-10-06T12:55:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Le 2 septembre 2025 est sortie la version 2.7 du logiciel de gestion de la relation client Crème CRM (sous licence AGPL-3.0), un peu plus d’un an après Creme 2.6 (5 août 2024).</p>
<p><img alt="Icone de Crème CRM" src="https://img.linuxfr.org/img/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f487962697264436f72702f6372656d655f63726d2f6d61696e2f6372656d652f7374617469632f636f6d6d6f6e2f696d616765732f6372656d655f3230302e706e67/creme_200.png" title="Source : https://raw.githubusercontent.com/HybirdCorp/creme_crm/main/creme/static/common/images/creme_200.png"/></p>
<p>Au programme notamment, le passage à Django 5.2, les types de fiches personnalisés et un système de processus automatisés. Les nouveautés sont détaillées dans la suite de la dépêche.</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116293" hreflang="fr" title="https://cremecrm.com/">Site officiel</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/116294" hreflang="fr" title="https://demos.cremecrm.com">Démo en ligne</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/116295" hreflang="en" title="https://github.com/HybirdCorp/creme_crm">Le dépôt de source</a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/116296" hreflang="en" title="https://hub.docker.com/r/cremecrm/cremecrm-demo">Images Docker de démo</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-description-du-logiciel">Description du logiciel</a></li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-principales-nouveaut%C3%A9s-de-la-version-27">Principales nouveautés de la version 2.7</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-le-passage-%C3%A0-django-52">Le passage à Django 5.2</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-les-types-de-fiches-personnalis%C3%A9s">Les types de fiches personnalisés</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-les-processus-automatis%C3%A9s">Les processus automatisés</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-quelques-autres-am%C3%A9liorations-notables">Quelques autres améliorations notables</a></li>
</ul>
</li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-le-futur">Le futur</a></li>
</ul>
<h2 id="toc-description-du-logiciel">Description du logiciel</h2>
<p>Crème CRM est un logiciel de <a href="https://fr.wikipedia.org/wiki/Gestion_de_la_relation_client">gestion de la relation client</a>, généralement appelé CRM (pour Customer Relationship Management). Il dispose évidemment des fonctionnalités basiques d’un tel logiciel :</p>
<ul>
<li>un annuaire, dans lequel on enregistre contacts et sociétés : il peut s’agir de clients, bien sûr, mais aussi de partenaires, prospects, fournisseurs, adhérents, etc. ;</li>
<li>un calendrier pour gérer ses rendez‐vous, appels téléphoniques, conférences, etc. ; chaque utilisateur peut avoir plusieurs calendriers, publics ou privés ;</li>
<li>les opportunités d’affaires, gérant tout l’historique des ventes ;</li>
<li>les actions commerciales, avec leurs objectifs à remplir ;</li>
<li>les documents (fichiers) et les classeurs.</li>
</ul>
<p>Crème CRM dispose en outre de nombreux modules optionnels le rendant très polyvalent :</p>
<ul>
<li>campagnes de courriels ;</li>
<li>devis, bons de commande, factures et avoirs ;</li>
<li>tickets, génération des rapports et graphiques…</li>
</ul>
<p>L’objectif de Crème CRM est de fournir un logiciel libre de gestion de la relation client pouvant convenir à la plupart des besoins, simples ou complexes. À cet effet, il propose quelques concepts puissants qui se combinent entre eux (entités, relations, filtres, vues, propriétés, blocs), et il est très configurable (bien des problèmes pouvant se résoudre par l’interface de configuration) ; la contrepartie est qu’il faudra sûrement passer quelques minutes dans l’interface de configuration graphique pour avoir quelque chose qui vous convienne vraiment (la configuration par défaut ne pouvant être optimale pour tout le monde). De plus, afin de satisfaire les besoins les plus particuliers, son code est conçu pour être facilement étendu, tel un cadriciel (<em>framework</em>).</p>
<p>Du côté de la technique, Crème CRM est codé notamment avec Python/Django et fonctionne avec les bases de données MySQL, SQLite et PostgreSQL.</p>
<h2 id="toc-principales-nouveautés-de-la-version-27">Principales nouveautés de la version 2.7</h2>
<p>Voici les changements les plus notables de cette version :</p>
<h3 id="toc-le-passage-à-django-52">Le passage à Django 5.2</h3>
<p>La nouvelle version LTS (Long Time Support, car maintenue pendant 3 ans) du cadriciel Web est sortie en avril 2025.</p>
<p>Pour les personnes qui déploient Creme, cela implique de nouvelles versions minimales :</p>
<ul>
<li>La version minimale de Python est maintenant la 3.10</li>
<li>Pour les systèmes de gestion de base de données (SGBD) les versions minimales sont SQLite 3.31, MySQL 8.0.11, PostgreSQL 14 &amp; MariaDB 10.5.</li>
</ul>
<p>Python 3.13 est désormais géré officiellement.</p>
<h3 id="toc-les-types-de-fiches-personnalisés">Les types de fiches personnalisés</h3>
<p>Il a bien sûr toujours été possible de créer ses propres types de fiches (entités) via du code (c’est même plutôt simple, notamment grâce aux outils que fournis Django).<br/>
Mais ici il s’agit de créer des types de manière visuelle, via l’interface de configuration. Pour créer un nouveau type il suffit de lui donner un nom (genre “Boutique”), ainsi que son nom au pluriel (donc “Boutiques” dans notre exemple). Ensuite des champs personnalisés peuvent être ajoutés, comme pour n’importe quel type de fiche. Et évidemment vous pouvez utiliser derrière tous les outils de configuration classiques pour construire l’interface qui vous convient (blocs, boutons, formulaires, menu…).</p>
<p>Techniquement, les tables correspondant aux types sont en fait toutes créés dès l’installation (mais seuls les types activés sont visibles) ce qui permet de fonctionner sereinement même sur les SGBD ne gérant pas les transactions de schéma. C’est pourquoi le nombre de types personnalisés est limité (à 20 en l’occurrence, cela devrait être largement suffisant en pratique).</p>
<p>Ce nouveau système était attendu depuis longtemps, et devrait encore un peu abaisser la barrière d’entrée en permettant d’éviter d’écrire du code dans pas mal de cas.</p>
<p><img alt="Création d’un nouveau type de fiche" src="https://img.linuxfr.org/img/68747470733a2f2f696d672e6879626972642e6f72672f6372656d652f696d672f6372656d6532372f6372656d6532375f46525f637573746f6d5f656e746974795f636f6e6669675f666f726d2e706e67/creme27_FR_custom_entity_config_form.png" title="Source : https://img.hybird.org/creme/img/creme27/creme27_FR_custom_entity_config_form.png"/></p>
<h3 id="toc-les-processus-automatisés">Les processus automatisés</h3>
<p>Ce nouveau système permet de programmer des actions qui seront effectuées de manière automatique lorsque certains évènements se produisent. Pour mieux comprendre les possibilités offertes, voici un processus créé lors de l’installation de Creme 2.7 : lorsqu’une fiche Opportunité d’affaire est modifiée et que son nouveau statut est un statut considéré comme gagné, alors la société cible de l’Opportunité devient cliente (si elle ne l’était pas déjà évidemment).</p>
<p>Dans cette première version, les évènements qui peuvent déclencher un processus sont :</p>
<ul>
<li>une fiche est créée</li>
<li>une fiche est modifiée</li>
<li>une propriété (il s’agit d’une sorte de <em>tag</em>) est ajoutée à une fiche</li>
<li>une relation est ajoutée entre 2 fiches</li>
</ul>
<p>Les actions actuellement disponibles sont :</p>
<ul>
<li>ajouter une propriété</li>
<li>ajouter une relation</li>
<li>envoyer un courriel</li>
</ul>
<p>Cette version initiale nous a demandé pas mal de travail afin de trouver une conception satisfaisante, mais de nombreuses améliorations sont d’ores et déjà prévues (notamment les évènements temporels &amp; une action qui peut modifier une fiche).</p>
<p>Les processus automatisés étaient, à l’instar des types personnalisés, très attendus ; et combiner ces 2 nouveaux systèmes ouvre pas mal de perspectives.</p>
<p><img alt="Un processus automatisé créé par un utilisateur pour les Activités" src="https://img.linuxfr.org/img/68747470733a2f2f696d672e6879626972642e6f72672f6372656d652f696d672f6372656d6532372f6372656d6532375f46525f776f726b666c6f775f636f6e6669675f646f6e652e706e67/creme27_FR_workflow_config_done.png" title="Source : https://img.hybird.org/creme/img/creme27/creme27_FR_workflow_config_done.png"/></p>
<p>La version plus détaillée est <a href="https://www.cremecrm.com/forum/showthread.php?tid=265">ici</a></p>
<h3 id="toc-quelques-autres-améliorations-notables">Quelques autres améliorations notables</h3>
<ul>
<li>La génération des numéros des Factures/Devis/Bons de commande a été entièrement revue. Elle se configure maintenant depuis l’interface (là où avant on pouvait juste rentrer des préfixes dans le fichier de configuration) et offre de nombreuses options.</li>
<li>La configuration des boutons peut désormais se faire par rôle (comme c’était déjà le cas avec les blocs, formulaires, etc.).</li>
<li>Les vues de liste &amp; les filtres peuvent être clonés (afin de gagner du temps, plutôt que de partir de zéro).</li>
<li>Le calendrier a été mis-à-jour (version 6.1.18 de la bibliothèque JavaScript FullCalendar), et un nouveau bloc permet d’afficher son calendrier sur la page d’accueil.</li>
<li>Pas mal de code de suppression a été amélioré, que ça soit pour empêcher plus souvent la suppression à cause de dépendances (plutôt que supprimer des choses en cascade), ou pour mieux afficher lesdites dépendances bloquantes.</li>
</ul>
<h2 id="toc-le-futur">Le futur</h2>
<p>La prochaine version devrait être plus courte que la 2.7 (qui a été un peu plus grosse que prévu à la base), afin de mieux coller aux sorties de Django. À l’année prochaine !</p>
</div><div><a href="https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-7.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140485/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/sortie-de-creme-crm-en-version-2-7#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>GuieA_7,Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>📣 Appel à volontaires PyConFR 2025</title>
        <link href="https://discuss.afpy.org/t/appel-a-volontaires-pyconfr-2025/2783" />
        <id>https://discuss.afpy.org/t/appel-a-volontaires-pyconfr-2025/2783</id>
        <updated>2025-10-04T21:14:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>La PyConFR 2025 approche et nous avons besoin de votre aide !<br/>
Que vous soyez habitué ou non des PyConFR, tout le monde est le·la bienvenue <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=14" title=":snake:" width="20"/></p>
<p>Si vous êtes intéressé·e, vous pouvez répondre à ce message en indiquant les domaines qui vous intéressent. N’hésitez pas également si  vous avez des questions <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=14" title=":slight_smile:" width="20"/></p>
<p>Nous recherchons des volontaires sur différentes tâches :</p>
<p><strong>Animation de l’atelier pour les enfants</strong> : le samedi après-midi a lieu l’atelier de programmation pour les enfants, en partenariat avec MixTeen. De nouvelles personnes pour encadrer l’atelier nous permettrait d’accueillir plus d’enfants. Des bénévoles de MixTeen sont déjà à l’animation et vous accompagneront.</p>
<p><strong>Coordination des sessions</strong> : signaler à l’orateurice qu’il reste 10min/5min, le temps restant pour les questions, indiquer quand le créneau est fini. Il faudrait au moins une personne par salle.</p>
<p><strong>Coordination des Lightning Talks</strong> : le dimanche matin, il y a également le créneau de Lightning Talks à coordonner (limiter le temps de présentation à 5/10min par sujet et le temps de questions).</p>
<p><strong>Accueil du public</strong> : le dimanche matin aussi a lieu l’Assemblée Générale de l’AFPy à laquelle toutes les personnes adhérentes seront. Il faudrait des personnes pour accueillir le public durant ce temps (pointer les gens, fournir un tour de cou + badge si besoin).</p>
<div class="md-table">
<table>
<thead>
<tr>
<th>—</th>
<th><img alt=":france:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/france.png?v=14" title=":france:" width="20"/> B003</th>
<th><img alt=":united_kingdom:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/united_kingdom.png?v=14" title=":united_kingdom:" width="20"/> B316</th>
<th><img alt=":france:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/france.png?v=14" title=":france:" width="20"/> B421</th>
<th><img alt=":france:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/france.png?v=14" title=":france:" width="20"/> C436</th>
</tr>
</thead>
<tbody>
<tr>
<td>samedi matin</td>
<td><a class="mention" href="https://discuss.afpy.org/u/lalmeras">@lalmeras</a></td>
<td>Gaston</td>
<td><a class="mention" href="https://discuss.afpy.org/u/reinula">@ReiNula</a></td>
<td><a class="mention" href="https://discuss.afpy.org/u/matthieusb">@matthieusb</a></td>
</tr>
<tr>
<td>samedi après-midi</td>
<td><a class="mention" href="https://discuss.afpy.org/u/petrus-v">@petrus-v</a></td>
<td>Ruud Van der Ham</td>
<td><a class="mention" href="https://discuss.afpy.org/u/captainkro">@CaptainKro</a></td>
<td><a class="mention" href="https://discuss.afpy.org/u/mounasb">@MounaSb</a></td>
</tr>
<tr>
<td>dimanche matin</td>
<td><a class="mention" href="https://discuss.afpy.org/u/lalmeras">@lalmeras</a></td>
<td>Habibi</td>
<td>Maylis</td>
<td></td>
</tr>
<tr>
<td>dimanche après-midi</td>
<td><a class="mention" href="https://discuss.afpy.org/u/matthieusb">@matthieusb</a></td>
<td>Habibi</td>
<td><a class="mention" href="https://discuss.afpy.org/u/amine">@amine</a></td>
<td><a class="mention" href="https://discuss.afpy.org/u/chadys">@Chadys</a></td>
</tr>
</tbody>
</table>
</div><p>Lightning Talks :</p>
<p>Accueil samedi matin : <a class="mention" href="https://discuss.afpy.org/u/matthieusb">@matthieusb</a></p>
<p>Accueil dimanche matin : Maylis, Johana, <a class="mention" href="https://discuss.afpy.org/u/lalmeras">@lalmeras</a>, Antonio</p>
<p>Atelier pour les enfants : <a class="mention" href="https://discuss.afpy.org/u/lalmeras">@lalmeras</a> <a class="mention" href="https://discuss.afpy.org/u/fefedu973">@Fefedu973</a></p>
<p><small>14 messages - 9 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/appel-a-volontaires-pyconfr-2025/2783">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Convocation à l’assemblée générale le dimanche 2 novembre à 9h</title>
        <link href="https://discuss.afpy.org/t/convocation-a-l-assemblee-generale-le-dimanche-2-novembre-a-9h/2781" />
        <id>https://discuss.afpy.org/t/convocation-a-l-assemblee-generale-le-dimanche-2-novembre-a-9h/2781</id>
        <updated>2025-10-04T09:18:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><em>Cette communication a été envoyée par mail à tous les membres présents et passés de l’association (2025, 2024, 2023).</em></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/convocation-a-l-assemblee-generale-le-dimanche-2-novembre-a-9h/2781/1">Assemblée Générale de l’AFPy</a></p>
<p>2025-11-02 09:00 (Europe/Paris) → 2025-11-02 09:55 (Europe/Paris)</p>
</div>
<p>Vous recevez ce courriel aujourd’hui car vous êtes ou avez été membre de l’association ces dernières années. De ce fait, si vous êtes toujours membre cette année, vous êtes cordialement convoqué pour notre assemblée générale annuelle qui se tiendra durant la PyConFR 2025 ce dimanche 2 novembre à 9h.</p>
<p>Pour rappel, la PyConFR 2025 se tient au Campus René Cassin de Lyon, du jeudi 30 octobre au dimanche 2 novembre (plus d’informations : <a class="inline-onebox" href="https://pycon.fr/2025/">À propos − PyConFR 2025</a>).<br/>
Le planning est disponible et les inscriptions sont ouvertes (plus d’informations : <a class="inline-onebox" href="https://www.pycon.fr/2025/fr/news.html">Actualités − PyConFR 2025</a>) !</p>
<p>Si ce n’est pas déjà fait, nous vous invitons à renouveler votre adhésion pour l’année 2025 en suivant les liens suivants :<br/>
<a class="inline-onebox" href="https://www.afpy.org/adherer">AFPY - Le site web de l'Association Francophone Python</a> ou <a href="https://www.helloasso.com/associations/afpy/adhesions/adhesion-2025-a-l-afpy">https://www.helloasso.com/associations/afpy/adhesions/adhesion-2025-a-l-afpy</a></p>
<p>Si vous ne savez pas si vous êtes à jour de cotisation, n’hésitez pas nous contacter par courriel à l’adresse <a href="mailto:secretaire@afpy.org">secretaire@afpy.org</a>.</p>
<p>Nous vous rappelons que si l’adhésion à l’association n’est pas obligatoire pour nous suivre et participer à nos événements, elle est néanmoins indispensable pour pouvoir voter aux résolutions lors de l’assemblée générale. De plus, votre adhésion est un soutien important pour les futures activités de l’association et, espérons-le, l’organisation d’une prochaine PyConFR, donc si vous pouvez vous le permettre nous vous en sommes reconnaissants !</p>
<p>L’ordre du jour de cette assemblée générale sera le suivant :</p>
<ul>
<li>Le Comité de Direction proposera un changement de domiciliation de l’association (avec vote d’approbation);</li>
<li>Le Comité de Direction proposera une mise à jour de la Charte de l’association (avec vote d’approbation). Vous pouvez d’ores et déjà prendre connaissance de la proposition sur cette pull request : <a class="inline-onebox" href="https://git.afpy.org/AFPy/afpy.org/pulls/12/files">#12 - MAJ de la charte - AFPy/afpy.org - La forge de l'AFPy</a>;</li>
<li>Le Comité de Direction proposera un reversement des potentiels bénéfices à différents organismes et projets libres utilisés par l’association (avec vote d’approbation);</li>
<li>La présidente présentera le bilan moral général de l’association (avec vote d’approbation);</li>
<li>Le trésorier présentera le bilan financier de l’association pour l’année passée et avec une projection éventuelle sur l’année en cours (avec vote d’approbation);</li>
<li>L’assemblée générale procédera ensuite au renouvellement d’une partie du Comité de Direction (CD) de l’association;</li>
<li>Le nouveau Comité de Direction proposera finalement un·e président·e à l’approbation de l’assemblée générale.</li>
</ul>
<p>Des questions ou remarques diverses non assujetties à un vote de la part de l’assemblée pourront également être évoquées par les membres du Bureau, du Comité de Direction et/ou par les membres, cotisants ou non, de l’association. N’hésitez pas à nous transmettre par avance en réponse à ce mail les sujets que vous souhaiteriez potentiellement aborder lors de cette assemblée générale.</p>
<p>Pour votre information, selon l’article 11 de nos statuts, il sera nécessaire de renouveller un tiers des membres du Comité de Direction de l’association.</p><aside class="onebox allowlistedgeneric">
<header class="source">
<img alt="" class="site-icon" height="123" src="https://git.afpy.org/assets/img/favicon.svg" width="152"/>
<a href="https://git.afpy.org/AFPy/gestion/src/branch/master/statuts/2023/statuts.rst#article-11" rel="noopener" target="_blank">La forge de l'AFPy</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img alt="" class="thumbnail" height="345" src="https://git.afpy.org/AFPy/gestion/-/summary-card" width="690"/></div>
<h3><a href="https://git.afpy.org/AFPy/gestion/src/branch/master/statuts/2023/statuts.rst#article-11" rel="noopener" target="_blank">gestion/statuts/2023/statuts.rst sur master</a></h3>
<p>gestion - Documents administratifs de l'AFPy.</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>Si vous êtes intéressé·es par rejoindre le Comité Directeur, n’hésitez pas à vous signaler par retour de mail et à nous poser les questions que vous pouvez avoir.<br/>
Un sujet a également été ouvert sur notre Discourse : <a class="inline-onebox" href="https://discuss.afpy.org/t/renouvellement-du-comite-directeur/2760">Renouvellement du Comité Directeur</a>.</p>
<p>Vous trouverez ci-dessous la liste de l’ensemble des membres au Comité de Direction avec leur année de début de mandat ainsi que leur poste éventuel au sein du Bureau :</p>
<ul>
<li>Antoine Rozo (Secrétaire, élu en 2020 − sortant)</li>
<li>Thomas Bouchet (Vice-Trésorier, élu en 2020 − sortant / démissionnaire)</li>
<li>Pierre Bousquié (Trésorier, élu en 2020 − sortant)</li>
<li>Laurine Leulliette (Vice-Secrétaire, élue en 2022)</li>
<li>Lucie Anglade (Présidente, élue en 2023 − démissionnaire)</li>
<li>Marc Debureaux (Vice-Président, élu en 2023)</li>
<li>Agnèr Haaser (élue en 2024)</li>
<li>Julie Rymer (élue en 2024)</li>
<li>Paul Guichon (élu en 2024)</li>
</ul>
<p>Dans le cas où il vous serait impossible de participer à l’assemblée générale de l’association, nous vous encourageons vivement à transmettre votre pouvoir à un autre membre (lui-même à jour de cotisation et présent lors de cette assemblée) de façon à ce que votre voix soit entendue. Pour cela, vous devez nous faire parvenir par courriel à l’adresse <a href="mailto:secretaire@afpy.org">secretaire@afpy.org</a> (en utilisant votre adresse d’adhésion) l’ensemble de vos coordonnées ainsi que celles du membre qui vous représentera en le mettant lui-même en copie de votre message et en y stipulant explicitement que vous lui accordez votre pouvoir de décision/vote.</p>
<p>Il ne sera pas possible de voter à distance.</p>
<p>Je profite également de cette communication pour vous rappeler les liens et ressources importantes pour rester en contact avec nous :</p>
<ul>
<li>Site de l’association : <a href="https://afpy.org">https://afpy.org</a></li>
<li>Site de la PyConFR 2025 : <a class="inline-onebox" href="https://www.pycon.fr/2025/">À propos − PyConFR 2025</a></li>
<li>Discord : <a class="inline-onebox" href="https://www.afpy.org/discord">AFPy</a></li>
<li>Discourse : <a href="https://discuss.afpy.org/">https://discuss.afpy.org/</a></li>
<li>Mastodon : <span class="mention">@AFPy</span>@mamot.fr</li>
<li>Bluesky : <span class="mention">@AFPy.mamot.fr.ap.brid.gy</span></li>
<li>Linkedin : <a class="inline-onebox" href="https://www.linkedin.com/company/afpy">Association Francophone Python (AFPy) | LinkedIn</a></li>
</ul>
<p>Merci à toutes et tous pour votre temps de lecture, j’espère vous retrouver à la PyConFR 2025 et surtout à notre assemblée générale ce dimanche 2 novembre à 9h !</p>
<p>À très bientôt !</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/convocation-a-l-assemblee-generale-le-dimanche-2-novembre-a-9h/2781">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Pourquoi Python reste le langage incontournable en 2025 ?</title>
        <link href="https://blog.jetbrains.com/pycharm/2025/09/why-is-python-so-popular/" />
        <id>https://blog.jetbrains.com/pycharm/2025/09/why-is-python-so-popular/</id>
        <updated>2025-10-03T14:23:57Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>De l’intelligence artificielle au développement web, en passant par la data science et l’automatisation, Python continue de dominer le paysage technologique en 2025. Découvrez les raisons de cette popularité persistante et pourquoi les développeur·se·s continuent de privilégier ce langage polyvalent.</p>
<a href="https://news.humancoders.com/t/python/items/39167-pourquoi-python-reste-le-langage-incontournable-en"><img src="https://blog.jetbrains.com/wp-content/uploads/2025/09/PC-social-BlogSocialShare-1280x720-2x-8.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/39167-pourquoi-python-reste-le-langage-incontournable-en#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/39167-pourquoi-python-reste-le-langage-incontournable-en">Pourquoi Python reste le langage incontournable en 2025 ?</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Geek Camp automne 2025</title>
        <link href="https://yaal.coop/blog/geek-camp-automne-2025" />
        <id>https://yaal.coop/blog/geek-camp-automne-2025</id>
        <updated>2025-10-02T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Retour sur ma participation au Geek Camp organisé par l'association Okiwi.</p>
<p>Geek Camp automne 2025
Organisé par l'association Okiwi, le Geek Camp rassemble le temps d'un week-end convivial la communauté tech bordelaise. L'organisation s'articule autour d'un grand forum ouvert, et qui dit ouvert, dit ouvert, donc si tu n'es ni de la tech ni de Bordeaux, tu es la·e bienvenu·e !</p>
<p>L'événement commence le vendredi soir et se termine le dimanche en début d'après midi. Et bien sûr, c'est ouvert aussi sur ces points : on peut ne venir que pour une partie ou juste pour dire bonjour ! C'est vraiment ouvert quoi. Le lieu, c'est la salle des fêtes de Ruffiac dans le 47. Un lieu très vert avec une jolie vue. Venez et vous verrez (inscriptions ici).</p>
<p>J'étais déjà venu à un Geek Camp juste avant de débuter chez Yaal Coop (encore merci Sam), lors de la session du printemps 2024. J'avais vraiment hâte de revenir pour profiter de cette ambiance si pleine de bienveillance et de passionné·e·s, curieux·se·s, brillant·e·s et animé·e·s d'un fort désir de partage.</p>
<p>Vendredi
Je suis arrivé le vendredi soir et déjà les discussions s'animaient tout en préparant les lieux et invoquant le feu pour les grillades.
Entre retrouvailles et discussions, la soirée s'est déroulée dans une ambiance de simplicité et de convivialité.</p>
<p>Sur un grand écran, Manu et Fabien présentent leurs projets en cours et invitent qui veut à participer à la résolution des problèmes du moment.
Autour des tables, on s'arrête pour échanger sur l'incroyable ergonomic split keyboard cutomisé de Romain.
Alors que certains n'ont pas encore regagné leur tente, nous partageons un moment ludique rythmé par les rires et les encouragements des observateurs.</p>
<p>Un forum ouvert, c'est quoi au fait ?
Merci de me poser la question, je suis toujours heureux d'expliquer le principe. Et c'est très simple. Chacun pourra proposer un (ou plusieurs) atelier, thème de discussion, activité, présentation, demande d'aide, etc. en proposant une heure de début et une durée approximative (et même un lieu pour se retrouver). Ce moment, c'est la place de marché.
Au préalable on a rappelé les règles et la loi qui régissent un forum ouvert:
- règle 1 : ça commence quand ça commence et ça finit quand ça finit. Oui, il n'est pas toujours facile de commencer à l'heure promise. Parfois, on commence même plus tôt et pas à l'endroit convenu. Parfois, au bout de 10 minutes, on a fait le tour, répondu au besoin et on n'a pas tenu le temps prévu. Parfois on déborde.
- règle 2 : les personnes présentes sont les bonnes personnes. On aurait peut-être aimé attirer cet expert·e sur le sujet, mais il fait autre chose. Alors on fait le sujet avec les personnes présentes. Peut-être même que celui qui voulait de l'aide va se retrouver à en apporter ou à initier. Et c'est très bien comme ça.
- règle 3 : ce qui arrive est la meilleur chose qui pouvait se passer. Les trois règles forment un ensemble cohérent. Je n'ai pas eu le temps de faire mon atelier ? Alors c'est que j'ai certainement fait ce que je devais faire. Et c'est tout simplement ce qui pouvait arriver de mieux.
- loi de la mobilité (dite des deux pieds) : si je suis quelque part et que je n'apprends rien et que je n'apporte rien, je dois faire autre chose. Ainsi, il est tout à fait admis de quitter un atelier et de revenir plus tard, il n'y a pas lieu de se vexer, on ne fait que se soumettre à cette loi.
Il est tout à fait autorisé de buller dans son coin ou de faire ce que l'on veut seul ou accompagné. On peut aussi papillonner en passant d'un atelier à l'autre ou butiner telle une abeille en apportant un peu ici et là.
Bref, un forum ouvert, c'est OUVERT dans tous les sens du terme. et, oui, ça a un côté assez magique, parce que ça fonctionne drôlement bien.</p>
<p>Samedi
Le samedi va commencer tout doucement, tellement doucement que l'ouverture du forum ouvert (la place du marché) ne se fera qu'en fin de matinée.</p>
<p>Les premiers ateliers commencent vers 15h. Nous sommes un peu plus d'une vingtaine de participants et tout le monde est ravi·e et impatient·e de s'y mettre. Bon nombre d'entre nous se rendent devant le tableau pour choisir leur premier rendez-vous. J'ai choisi de rejoindre Sam et Manu qui préparaient un futur atelier pour Agenux. Un fizzbuzz en C#, SOLID, CUPID and cute DDD. Je ne connais pas le C#. J'ai l'habitude de ne pas savoir, je suis junior. Alors je m'assois et j'écoute, je regarde. Bonne nouvelle, je ne comprends certes pas les problèmes, mais j'arrive à suivre le fil. Alors, ça me va.</p>
<p>Vers 16h, je rejoins Arnaud qui souhaite tester un atelier de dev qui s'appuie sur le lambda-calcul pour le meet up lambda Nantes. Là, clairement, je n'ai pas le niveau et en plus, c'est la première fois que j'entends parler de lambda-calcul. Mais ça m'intéresse de suivre et Arnaud me fait rire. Je vais passer un bon moment à suivre les retours et les difficultés à capter les ressorts de l'exercice par les participants.</p>
<p>Vers 18h, je vais participer à la présentation d'un outil de craft présenté par Fabien. Son outil vise à identifier les difficultés d'une tâche afin d'évaluer aussi ce que je peux apprendre grâce aux autres, par moi-même ou ce qui doit être reporté ou vite abattu pour permettre d'avancer sans chercher à faire de la qualité. Nous échangeons à 4 ou 5 autour du sujet, proposons des amélioration, soulevons des question pour faire évoluer l'outil.</p>
<p>Je n'ai malheureusement pas eu le temps d'animer mon atelier : "gagner la confiance client". C'est ce qui devait arriver. Mais alors que la journée touche à sa fin, Florimond puis Fabien (un autre Fabien) me disent qu'ils auraient aimé y assister. Alors je décale mon atelier au dimanche matin 10h.</p>
<p>Le soir venu, le Geek Camp prend l'allure d'une soirée entre amis. On parle de tout et de rien, on rigole beaucoup, on échange nos idées, on parle de nous. Un beau moment entouré de gens qui ne jugent pas, juste du partage.</p>
<p>Certains enchaîneront les petits jeux, d'autre feront un gros jeu et, Arnaud, Guillaume et moi un trop gros. 3h pour le premier tour seulement. Arnaud avait eu le courage de découvrir les règles de ce wargame imposant durant la journée. C'était vraiment chouette : les bonnes personnes qui vivent ce qui pouvait se passer de meilleur.</p>
<p>Dimanche
Le dimanche matin, je vais attendre que Florimond et Fabien soient prêts et je lance ma présentation. Nous serons rejoints par 6 ou 7 personnes. Je suis content de voir que le sujet intéresse. Je réponds à quelques questions puis on continue sur le sujet avant de dériver et de beaucoup rire de l'anecdote du chat de Florimond.</p>
<p>En fin de matinée, alors que Mikael remplace Xavier à la crêpière, nous faisons la clôture du forum ouvert. On va tous pouvoir s'exprimer en se promettant de tout faire pour que le prochain dure plus longtemps. Après tout avec le télétravail, ça devrait être possible. Certains se motivent pour organiser une promenade dans les environs.</p>
<p>Après un dernier repas, et un dernier coup d'éponge, chacun rentre chez soi, des souvenirs pleins la tête avec la ferme intention de revenir profiter le plus tôt possible.</p>
<p>Pour conclure, je tiens à remercier l'engagement et l'énergie de Xavier, Stéfanie et Sam (membres du bureau d'Okiwi) qui ont permis de faire de cette session une nouvelle réussite. Merci à vous !</p>
            </div>
        </content>
        <author>
            <name>Sébastien Birolleau &lt;sebastien@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>sqlramen un remplacement à sqlsoup</title>
        <link href="https://linuxfr.org/users/jul/journaux/sqlramen-un-remplacement-a-sqlsoup" />
        <id>https://linuxfr.org/users/jul/journaux/sqlramen-un-remplacement-a-sqlsoup</id>
        <updated>2025-10-02T14:54:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Alors que je pleurais la disparition de sqlsoup et ré-écrivais pour la 5é fois le code <em>minimal</em> pour le remplacer je me suis dit ; tu pourrais offrir un module équivalent.</p>
<h2 id="toc-sqlramen-un-peu-comme-sqlsoup">SQLRamen, un peu comme SQLSoup</h2>
<p>SQLRamen offre une interface minimaliste au dessus de sqlalchemy pour avoir une console introspective sur une base de données… Ce qui est avec une API différente ce que faisait SQLSoup qui a disparu avec sqlalchemy 2.</p>
<p>Le code est minimal et est basé sur <a href="https://docs.sqlalchemy.org/en/stable/orm/extensions/automap.html">automap</a>.</p>
<h3 id="toc-installation">Installation</h3>
<pre><code>python -m pip install sqlramen
</code></pre>
<h3 id="toc-exemple-">Exemple :</h3>
<pre><code class="python"><span class="kn">from</span> <span class="nn">sqlramen</span> <span class="kn">import</span> <span class="n">SQLRamen</span>
<span class="n">db</span> <span class="o">=</span> <span class="n">SQLRamen</span><span class="p">(</span><span class="s2">"sqlite:///../pdca/aide"</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">user</span><span class="p">)</span><span class="o">.</span><span class="n">filter_by</span><span class="p">(</span><span class="n">email</span><span class="o">=</span><span class="s2">"j@j.com"</span><span class="p">)</span><span class="o">.</span><span class="n">one</span><span class="p">()</span>
<span class="p">[</span> <span class="n">l</span><span class="o">.</span><span class="n">message</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">user</span><span class="o">.</span><span class="n">comment_collection</span> <span class="p">]</span>
<span class="c1"># ['SCAM Manual\r\n\r\nA complete guide to create a guide with scam',</span>
<span class="c1"># ...</span>
<span class="c1">#  'future plan',</span>
<span class="c1">#  'further down']</span>
<span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">comment</span><span class="o">.</span><span class="n">message</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">comment</span><span class="o">.</span><span class="n">user</span>
    <span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">email</span><span class="o">==</span><span class="s2">"j@j.com"</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="c1"># same</span>
<span class="k">print</span><span class="p">([</span><span class="n">l</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">db</span><span class="o">.</span><span class="n">table</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">__table__</span><span class="o">.</span><span class="n">c</span><span class="p">])</span>
<span class="c1"># [Column('id', INTEGER(), table=&lt;user&gt;, primary_key=True, nullable=False),</span>
<span class="c1"># Column('pic_file', TEXT(), table=&lt;user&gt;),</span>
<span class="c1"># Column('name', TEXT(), table=&lt;user&gt;, nullable=False),</span>
<span class="c1"># Column('email', TEXT(), table=&lt;user&gt;, nullable=False),</span>
<span class="c1"># Column('secret_token', TEXT(), table=&lt;user&gt;),</span>
<span class="c1"># Column('secret_password', TEXT(), table=&lt;user&gt;, nullable=False)]</span>
<span class="n">db</span><span class="o">.</span><span class="n">raw</span><span class="p">(</span><span class="s2">"select * from comment limit 5"</span><span class="p">)</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="c1">#[('2025-01-12 12:52:09', 1, 1, None, 'SCAM Manual\r\n\r\nA complete guide to create a guide with scam', None, 'story'),</span>
<span class="c1"># ('2025-01-12 13:28:14', 2, 1, 1, 'Synopsis\r\n\r\nA frontend to a pandoc toolchain to build a book in a supposedly new way.', None, 'story_item'),</span>
<span class="c1"># ('2025-01-12 13:28:47', 3, 1, 1, 'How to install and start it\r\n', None, 'story_item'),</span>
<span class="c1"># ('2025-01-12 13:29:48', 4, 1, 1, 'walkthrough to create this manual with the tool\r\n\r\nFirst post//landing page', None, 'story_item'),</span>
<span class="c1"># ('2025-01-12 13:30:23', 5, 1, 3, 'Quickstart', None, 'comment')]</span></code></pre>
<h3 id="toc-db_introspect">db_introspect</h3>
<p>Le module est livré avec un grapheur de base de données dont voici un exemple :</p>
<pre><code class="bash">db_introspect sqlite:///../pdca/aide <span class="o">&amp;&amp;</span> xdot out.dot</code></pre>
<p>Ce qui donne le résultat suivant </p>
<p><img alt="digramme entité relation" src="https://img.linuxfr.org/img/68747470733a2f2f6769746875622e636f6d2f6a756c2f73716c72616d656e2f7261772f6d61696e2f6f75742e706e673f7261773d74727565/out.png?raw=true" title="Source : https://github.com/jul/sqlramen/raw/main/out.png?raw=true"/></p>
<div><a href="https://linuxfr.org/users/jul/journaux/sqlramen-un-remplacement-a-sqlsoup.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140488/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jul/journaux/sqlramen-un-remplacement-a-sqlsoup#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Jul</name>
        </author>
    </entry>
    <entry>
        <title>Python - « Libre à vous ! » du 23 septembre 2025 - Podcasts et références</title>
        <link href="https://linuxfr.org/news/python-libre-a-vous-du-23-septembre-2025-podcasts-et-references" />
        <id>https://linuxfr.org/news/python-libre-a-vous-du-23-septembre-2025-podcasts-et-references</id>
        <updated>2025-10-01T08:57:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>255e émission <a href="https://libreavous.org">« Libre à vous ! »</a> de l’April. <a href="https://media.april.org/audio/radio-cause-commune/libre-a-vous/emissions/20250923/libre-a-vous-20250923.ogg">Podcast</a> et programme :</p>
<ul>
<li>sujet principal : le langage de programmation Python</li>
<li>La chronique Le truc que (presque) personne n'a vraiment compris mais qui nous concerne toutes et tous de Benjamin Bellamy sur les VPNs</li>
<li>Une nouvelle Lecture buissonnière de Vincent Calame sur l'ouvrage d'Éric Sadin, « La vie algorithmique »</li>
<li>Quoi de Libre ? Actualités et annonces concernant l'April et le monde du Libre</li>
</ul>
<p>Rendez‐vous en direct chaque mardi de 15 h 30 à 17 h sur 93,1 FM en Île‐de‐France. L’émission est diffusée simultanément sur le <a href="https://cause-commune.fm/">site Web de la radio Cause Commune</a>.</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116271" hreflang="fr" title="https://media.april.org/audio/radio-cause-commune/libre-a-vous/emissions/20250923/libre-a-vous-20250923.ogg">Podcast de l'émission </a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/116272" hreflang="fr" title="https://www.libreavous.org/255">Les références pour l'émission et les podcasts par sujets </a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/116273" hreflang="fr" title="https://www.librealire.org/emission-libre-a-vous-diffusee-mardi-23-septembre-2025-sur-radio-cause-commune">La transcription de l'émission </a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/116274" hreflang="fr" title="https://libreavous.org/rss">S'abonner au podcast </a></li><li>lien nᵒ 5 : <a href="https://linuxfr.org/redirect/116275" hreflang="fr" title="https://www.libreavous.org/listes-de-diffusion">S'abonner à la lettre d'actus </a></li><li>lien nᵒ 6 : <a href="https://linuxfr.org/redirect/116276" hreflang="fr" title="https://www.libreavous.org/">Libre à vous ! </a></li><li>lien nᵒ 7 : <a href="https://linuxfr.org/redirect/116277" hreflang="fr" title="https://cause-commune.fm/">Radio Cause Commune </a></li></ul><div></div><div><a href="https://linuxfr.org/news/python-libre-a-vous-du-23-septembre-2025-podcasts-et-references.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140461/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/python-libre-a-vous-du-23-septembre-2025-podcasts-et-references#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Etienne Gonnu,Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>Comment protéger vos serveurs et lutter efficacement contre les crawlers d’IA</title>
        <link href="https://bearstech.com/societe/blog/comment-proteger-vos-serveurs-et-lutter-efficacement-contre-les-crawlers-dia" />
        <id>https://bearstech.com/societe/blog/comment-proteger-vos-serveurs-et-lutter-efficacement-contre-les-crawlers-dia</id>
        <updated>2025-10-01T07:59:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>emazurier</name>
        </author>
    </entry>
    <entry>
        <title>L&#39;IA devenue outil du quotidien</title>
        <link href="https://linuxfr.org/users/funix/journaux/l-ia-devenue-outil-du-quotidien" />
        <id>https://linuxfr.org/users/funix/journaux/l-ia-devenue-outil-du-quotidien</id>
        <updated>2025-09-28T14:07:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>'lut,</p>
<p>Vous me direz, encore un journal sur l'IA ! C'est un sujet globalement plutôt décrié sur ce site qui met en exergue surtout ses méfaits, mais je tenais à faire part de mon expérience car ça peut être également un super outil du quotidien. A tel point que j'ai quasiment laissé tomber les moteurs de recherche, dont le premier d'entre eux et mon premier réflexe est maintenant d'abord de consulter chatgpt. Pourquoi chatgpt ? Simplement parce que je trouve encore les autres bien moins performants.</p>
<p>Je le consulte pour les petites problématiques du quotidien et du bricoleur du dimanche que je suis, quand je regarde mon historique de consultation, ça va aussi bien de la recherche d'une référence d'une pièce auto et la manière de l'installer, rattraper une anchoïade, installer un programmateur dans un tableau électrique, faire un joint d'étanchéité sous l'eau ou trouver le mode d'emploi d'un réfrigérateur ! Et dans le domaine informatique, ça couvre aussi bien des scripts bash pour divers usage et des problèmes variés rencontrés sur divers logiciels.<br/>
Tout n'est surtout pas à prendre au pied de la lettre, il y a parfois des erreurs grossières, des informations datées voire obsolètes, il lui arrive également de tourner en rond et de radoter sans avancer, mais le plus souvent il me donne les bonnes pistes et par itération successive, j'arrive très souvent à mes fins pour résoudre mon problème initial.</p>
<p>S'il fallait illustrer mes propos par un exemple concret, dans <a href="https://linuxfr.org/users/funix/journaux/souriez-vous-etes-filme">un précédent journal</a> j'avais évoqué que j'avais déployé chez moi un système de vidéosurveillance basé sur zoneminder. J'avais acheté un ensemble de caméras adhoc dont certains à bas coût d'une vingtaine d'euros dont les caractéristiques semblaient intéressantes pour l'usage que je voulais en faire. A vrai dire je n'ai jamais pu installer ces caméras bas coût car l'adresse du flux vidéo change régulièrement ce qui les rend inutilisables pour les logiciels  comme zoneminder ou frigate qui ne gèrent que les adresses fixes, contraignant à utiliser l'application propriétaire Android fournie avec.</p>
<p>J'ai buté des mois sur ce problème en tentant vainement diverses solutions et en mettant au point sans succès très laborieusement un script python. Dernièrement j'ai fait appel à chatgpt et en 2h de temps tout était en place. chatgpt m'a aidé à créer un script qui récupère à intervalle régulier l'adresse du stream vidéo, adresse qu'il enregistre ensuite dans le fichier de configuration de mediamtx, serveur de flux vidéo qui rediffuse le flux avec une adresse fixe accessible de zoneminder ou frigate.<br/>
Je ne suis pas sûr que j'y serais arrivé seul, ou alors au bout de je ne sais combien d'heure de vaines programmations. Je me rends compte que chatgpt a évolué également, car je lui avais posé la même question il y a plusieurs mois, il a été incapable d'y répondre et ne m'avait pas donné à l'époque de pistes sérieuses pour avancer. Pour autant je ne pense pas que l'IA va envoyer les développeurs au chômage, je pense plutôt qu'il va les aider à être bien plus efficace.</p>
<p>Il en reste pas moins que ceux qui sont intéressés par ce sujet spécifique peuvent toujours consulter <a href="https://www.funix.org/fr/linux/index.php?ref=videosurveillance#G%C3%A9rer_les_cam%C3%A9ras_dont_ladresse_du">cette page</a> pour retrouver ce fameux script python.</p>
<div><a href="https://linuxfr.org/users/funix/journaux/l-ia-devenue-outil-du-quotidien.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140424/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/funix/journaux/l-ia-devenue-outil-du-quotidien#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Funix</name>
        </author>
    </entry>
    <entry>
        <title>Le planet de l&#39;AFPy a besoin d&#39;aide sur du HTML/CSS</title>
        <link href="https://discuss.afpy.org/t/le-planet-de-lafpy-a-besoin-daide-sur-du-html-css/2775" />
        <id>https://discuss.afpy.org/t/le-planet-de-lafpy-a-besoin-daide-sur-du-html-css/2775</id>
        <updated>2025-09-26T21:24:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjoir les gens,</p>
<p>j’essaye de mettre de la pagination sur le <a href="https://planet.afpy.org">planet de l’AFPy</a>. Mais je pense ne pas être à la hauteur, en <a href="https://framagit.org/JulienPalard/makemake-themes/-/commit/6d13536b086a94522d1ae0249fb1c219c0d4546c">un commit</a> j’ai tout cassé, l’aside n’est plus aside, les liens précédent/suivant sont placés n’importe où, l’enfer.</p>
<p>Quelqu’un a le temps de tenter de faire ça propre ?</p>
<p><small>4 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/le-planet-de-lafpy-a-besoin-daide-sur-du-html-css/2775">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Abuser de yahi -un équivalent d&#39;awstats- pour grapher des CSV</title>
        <link href="https://discuss.afpy.org/t/abuser-de-yahi-un-equivalent-dawstats-pour-grapher-des-csv/2774" />
        <id>https://discuss.afpy.org/t/abuser-de-yahi-un-equivalent-dawstats-pour-grapher-des-csv/2774</id>
        <updated>2025-09-26T20:18:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a class="anchor" href="https://discuss.afpy.org#p-11707-propos-de-yahi-1" name="p-11707-propos-de-yahi-1"></a>à propos de yahi</h1>
<p>Alors qu’awstats annonce sa dernière version, <a href="https://github.com/jul/yahi" rel="noopener nofollow ugc">yahi</a> (le lien inclus un lien vers la démo de la sortie) est un équivalent installable par pip d’analyse de journaux web normalement destiné à sortir des stats d’aggrégation, <strong>maintenu</strong>.</p>
<p>Son usage est suffisamment versatile pour s’adresser à tout type de d’agrégation de serveur parsable par regexp.</p>
<h1><a class="anchor" href="https://discuss.afpy.org#p-11707-dtourner-yahi-pour-grapher-des-csv-2" name="p-11707-dtourner-yahi-pour-grapher-des-csv-2"></a>détourner yahi pour grapher des CSV</h1>
<p>Comme ce module est assez simple il peut être <a href="https://linuxfr.org/users/jul/journaux/detourner-yahi-grapheur-de-journaux-web-pour-faire-des-graphs-de-csv" rel="noopener nofollow ugc">facilement détourné</a> pour grapher des CSV.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/abuser-de-yahi-un-equivalent-dawstats-pour-grapher-des-csv/2774">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>jul</name>
        </author>
    </entry>
    <entry>
        <title>détourner yahi (grapheur de journaux web) pour faire des graphs de CSV</title>
        <link href="https://linuxfr.org/users/jul/journaux/detourner-yahi-grapheur-de-journaux-web-pour-faire-des-graphs-de-csv" />
        <id>https://linuxfr.org/users/jul/journaux/detourner-yahi-grapheur-de-journaux-web-pour-faire-des-graphs-de-csv</id>
        <updated>2025-09-26T12:04:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 id="toc-yahi">Yahi</h2>
<p>Yahi est un analogue de <a href="https://linuxfr.org/news/awstats-8-0-est-sorti">awstats</a> qui a pour particularité de générer un fichier HTML tout en un (qui nécessite javascript) pour fournir les différentes pages de statistiques (essentiellement une carte geoip, des histogrammes et séries temporelles).</p>
<p>Mais, comme je suis un pervers pépère, je me suis amusé à voir si il n'était pas possible de l'utiliser aussi pour analyser des fichiers <a href="https://fr.wikipedia.org/wiki/CSV" title="Définition Wikipédia">CSV</a>.</p>
<h2 id="toc-exemple-1-dont-utilisation-de-regexp-pour-parser-un-csv">Exemple 1: DONT: utilisation de <a href="https://fr.wikipedia.org/wiki/regexp" title="Définition Wikipédia">regexp</a> pour parser un CSV</h2>
<p>Dans le cadre de <a href="https://linuxfr.org/users/jul/journaux/la-chronique-du-bot-bluesky-retrospective">mon bot bluesky</a> je génère un CSV de stat qui a une structure sur laquelle on peut <strong>exceptionnellement</strong> appliquer une regexp : </p>
<p>timestamp (float), nombre de post français (int), nombre de posts totaux (int),?…</p>
<p>Le code est simple ::</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">archery</span> <span class="kn">import</span> <span class="n">mdict</span>
<span class="kn">from</span> <span class="nn">yahi</span> <span class="kn">import</span> <span class="n">notch</span><span class="p">,</span> <span class="n">shoot</span>
<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">dump</span>
<span class="kn">import</span> <span class="nn">re</span>


<span class="n">context</span><span class="o">=</span><span class="n">notch</span><span class="p">(</span>
    <span class="n">off</span><span class="o">=</span><span class="s2">"user_agent,geo_ip"</span><span class="p">,</span>
    <span class="n">log_format</span><span class="o">=</span><span class="s2">"custom"</span><span class="p">,</span>
    <span class="n">output_format</span><span class="o">=</span><span class="s2">"json"</span><span class="p">,</span>
    <span class="n">date_pattern</span><span class="o">=</span><span class="s2">"</span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span>
    <span class="n">log_pattern</span><span class="o">=</span><span class="s2">"""^(?P&lt;datetime&gt;[^,]+),</span>
<span class="s2">    (?P&lt;nb_fr&gt;[^,]+),</span>
<span class="s2">    (?P&lt;nb_total&gt;[^,]+),?.*</span>
<span class="s2">    $"""</span><span class="p">)</span>

<span class="n">date_formater</span><span class="o">=</span> <span class="k">lambda</span> <span class="n">dt</span> <span class="p">:</span><span class="s2">"</span><span class="si">%s</span><span class="s2">-</span><span class="si">%s</span><span class="s2">-</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span> <span class="n">dt</span><span class="o">.</span><span class="n">year</span><span class="p">,</span> <span class="n">dt</span><span class="o">.</span><span class="n">month</span><span class="p">,</span> <span class="n">dt</span><span class="o">.</span><span class="n">day</span><span class="p">)</span>
<span class="n">res</span><span class="o">=</span> <span class="n">shoot</span><span class="p">(</span>
        <span class="n">context</span><span class="p">,</span>
        <span class="k">lambda</span> <span class="n">data</span><span class="p">:</span> <span class="n">mdict</span><span class="p">({</span>
            <span class="s2">"date_fr"</span> <span class="p">:</span>
                <span class="n">mdict</span><span class="p">({</span> <span class="n">date_formater</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"_datetime"</span><span class="p">])</span> <span class="p">:</span> 
                    <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"nb_fr"</span><span class="p">])</span> <span class="p">}),</span>
            <span class="s2">"hour_fr"</span> <span class="p">:</span> 
                <span class="n">mdict</span><span class="p">({</span> <span class="s2">"</span><span class="si">%02d</span><span class="s2">"</span> <span class="o">%</span> <span class="n">data</span><span class="p">[</span><span class="s2">"_datetime"</span><span class="p">]</span><span class="o">.</span><span class="n">hour</span> <span class="p">:</span> 
                    <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"nb_fr"</span><span class="p">])</span> <span class="p">}),</span>
            <span class="s2">"date_all"</span> <span class="p">:</span> 
                <span class="n">mdict</span><span class="p">({</span> <span class="n">date_formater</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"_datetime"</span><span class="p">])</span> <span class="p">:</span> 
                    <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"nb_total"</span><span class="p">])</span> <span class="p">}),</span>
            <span class="s2">"hour_all"</span> <span class="p">:</span> 
                <span class="n">mdict</span><span class="p">({</span> <span class="s2">"</span><span class="si">%02d</span><span class="s2">"</span> <span class="o">%</span> <span class="n">data</span><span class="p">[</span><span class="s2">"_datetime"</span><span class="p">]</span><span class="o">.</span><span class="n">hour</span> <span class="p">:</span> 
                    <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"nb_total"</span><span class="p">])</span> <span class="p">}),</span>
            <span class="s2">"total"</span> <span class="p">:</span> <span class="mi">1</span>
        <span class="p">})</span>
    <span class="p">)</span>
<span class="n">dump</span><span class="p">(</span><span class="n">res</span><span class="p">,</span><span class="nb">open</span><span class="p">(</span><span class="s2">"data.js"</span><span class="p">,</span><span class="s2">"w"</span><span class="p">),</span>  <span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span></code></pre>
<p>Ce code génère le fichier data.js dans les conventions qui suivent les attendus du fichier de données yahi</p>
<p>date_ … correspond à un histogramme de temps<br/>
hour_ … correspond à un histogramme par heure</p>
<p>Il suffit de faire :<br/>
<code><br/>
yahi_all_in_one_maker &amp;&amp; firefox aio.html<br/>
</code>Pour voir les résultats dont ci joint sont deux exemples :</p>
<p><img alt="par heure pour les posts fr" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f322e706e67/csv_2.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_2.png"/></p>
<p><img alt="par date pour les posts fr" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f312e706e67/csv_1.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_1.png"/></p>
<h2 id="toc-exemple-2-utilisation-brutale-avec-csv-dictreader">Exemple 2: utilisation brutale avec CSV DictReader</h2>
<p>Pour ce cas, j'ai pris le fichier CSV que m'a imprudemment envoyé france travail avec le listing des 10 000 chômeurs de mon coin ayant la structure suivante :</p>
<p>id opaque, civilité, prénom, nom, email du conseiller</p>
<p>pour bâtir les histogrammes de </p>
<ul>
<li>combien chaque conseiller suit de chômeur, </li>
<li>quelle est la fréquence des prénoms (et ce que cela révèle)</li>
</ul>
<p>Là encore, le code est assez simple :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">csv</span> <span class="kn">import</span> <span class="n">DictReader</span>
<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">dump</span>
<span class="kn">from</span> <span class="nn">archery</span> <span class="kn">import</span> <span class="n">mdict</span>

<span class="n">res</span><span class="o">=</span><span class="n">mdict</span><span class="p">()</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"/home/jul/Téléchargements/GEMESCAPEG.csv"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">DictReader</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
        <span class="n">res</span><span class="o">+=</span><span class="n">mdict</span><span class="p">(</span>
            <span class="n">by_ref</span> <span class="o">=</span> <span class="n">mdict</span><span class="p">({</span><span class="n">l</span><span class="p">[</span><span class="s2">"Referent"</span><span class="p">]:</span> <span class="mi">1</span><span class="p">}),</span>
            <span class="n">by_prenom</span><span class="o">=</span><span class="n">mdict</span><span class="p">({</span><span class="n">l</span><span class="p">[</span><span class="s2">"Prenom"</span><span class="p">]:</span><span class="mi">1</span><span class="p">}))</span>

<span class="n">dump</span><span class="p">(</span><span class="n">res</span><span class="p">,</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"data.js"</span><span class="p">,</span> <span class="s2">"w"</span><span class="p">),</span> <span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span></code></pre>
<p>Et là la magie de la convention de nommage indique que l'on veut des histogramme triés en forme de top 40</p>
<p>Il ne reste plus qu'à générer la page web …<br/>
<code><br/>
yahi_all_in_one_maker &amp;&amp; firefox aio.html<br/>
</code>Et l'on à les graphs suivants : </p>
<p>(le premier est tronqué pour respecter le RGPD)</p>
<h3 id="toc-le-nombre-de-chômeurs-par-conseiller">le nombre de chômeurs par conseiller</h3>
<p><img alt="le nombre de chômeurs par conseiller" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f332e706e67/csv_3.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_3.png"/></p>
<p>Ce qui nous apprend qu'un conseiller suit en moyenne 250 chômeurs, et que certains à plus de 500 risquent le burnout</p>
<h3 id="toc-la-fréquence-des-prénoms">la fréquence des prénoms</h3>
<p><img alt="la fréquence des prénoms" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f342e706e67/csv_4.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_4.png"/></p>
<p>Ce qui nous apprend quand on met en regard de quand les prénoms les plus courants avaient du succès que vaut mieux pas être vieux et au chômage (tarte à la crème) si on veut retrouver du boulot.</p>
<p>Voir la fréquence des prénoms suivants (source INSEE)<br/>
<img alt="la fréquence des prénoms" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f352e706e67/csv_5.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_5.png"/></p>
<p><img alt="la fréquence des prénoms" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f362e706e67/csv_6.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_6.png"/></p>
<p><img alt="la fréquence des prénoms" src="https://img.linuxfr.org/img/68747470733a2f2f796168692e72656164746865646f63732e696f2f656e2f6c61746573742f5f696d616765732f6373765f372e706e67/csv_7.png" title="Source : https://yahi.readthedocs.io/en/latest/_images/csv_7.png"/></p>
<h2 id="toc-est-ce-une-bonne-idée-quand-on-est-chômeur-de-faire-du-logiciel-libre">Est-ce une bonne idée quand on est chômeur de faire du logiciel libre</h2>
<p>J'en ai discuté avec ma conseillère qui m'a dit : pour ne pas être contrôler il est bien dans la partie <s>mouchard</s> projet de votre interface de france travail de rajouter des projets, le plus évitant les contrôles, et vous pouvez tout à fait rajouter vos contributions à du logiciel libre comme étant de l'auto-formation.</p>
<div><a href="https://linuxfr.org/users/jul/journaux/detourner-yahi-grapheur-de-journaux-web-pour-faire-des-graphs-de-csv.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140404/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jul/journaux/detourner-yahi-grapheur-de-journaux-web-pour-faire-des-graphs-de-csv#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Jul</name>
        </author>
    </entry>
    <entry>
        <title>Comment optimiser vos images de conteneurs Docker</title>
        <link href="https://bearstech.com/societe/blog/comment-optimiser-vos-images-de-conteneurs" />
        <id>https://bearstech.com/societe/blog/comment-optimiser-vos-images-de-conteneurs</id>
        <updated>2025-09-24T10:00:33Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>PyConFR 2025, planning et inscriptions</title>
        <link href="https://linuxfr.org/news/pyconfr-2025-planning-et-inscriptions" />
        <id>https://linuxfr.org/news/pyconfr-2025-planning-et-inscriptions</id>
        <updated>2025-09-24T07:57:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>La PyConFR 2025 a lieu du jeudi 30 octobre au dimanche 2 novembre au Campus René Cassin à Lyon. Le planning est en ligne et les inscriptions sont ouvertes !</p>
<p>Comme toujours, l’évènement est gratuit et l’inscription est obligatoire.</p>
<p>Les deux premiers jours de la conférence seront occupés par les sprints. Et les deux jours suivants seront dédiés aux conférences (longues et courtes) et ateliers.</p>
<p>Trois keynotes sont au programme :</p>
<ul>
<li>Embracing Weird Code, d’Ivana Kellyer</li>
<li>Le rêve de tout enfant - devenir DBA ?, de Karen Jex</li>
<li>Être un·e allié·e du numérique pour tou·te·s en environnement hostile, de Morgane Rozenn Hauguel</li>
</ul>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116233" hreflang="fr" title="https://www.pycon.fr/2025/">PyConFR 2025</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/116234" hreflang="fr" title="https://www.pycon.fr/2025/fr/schedule.html">Programme de la PyConFR 2025</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/116235" hreflang="fr" title="https://www.pycon.fr/2025/fr/schedule.html#register">Inscriptions</a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/116236" hreflang="fr" title="https://www.pycon.fr/2025/fr/conduct.html">Code de conduite</a></li><li>lien nᵒ 5 : <a href="https://linuxfr.org/redirect/116237" hreflang="fr" title="https://www.pycon.fr/2025/fr/support.html">Soutenir l’évènement</a></li><li>lien nᵒ 6 : <a href="https://linuxfr.org/redirect/116238" hreflang="fr" title="https://www.afpy.org/">Association Francophone Python</a></li></ul><div><p>Un atelier de programmation pour les enfants (à partir d’environ 7 ans) a lieu le samedi après-midi.</p>
<p>Un espace enfants (de 3 ans à 12 ans) est aussi mis à disposition le samedi et dimanche gratuitement et sur inscription.</p>
<p>Un déjeuner PyLadies a également lieu durant la conférence. Un des objectifs est de tisser des liens entre la communauté PyLadies et le reste de la communauté Python francophone.</p>
<p>En plus du traditionnel repas du samedi soir, des visites guidées de Lyon sont aussi possibles les jeudi et vendredi soir, toujours sur inscription.</p>
<p>Enfin, le dimanche matin, l’AFPy tient son assemblée générale. Si vous souhaitez y voter, assurez-vous d’être à jour de cotisation. </p>
</div><div><a href="https://linuxfr.org/news/pyconfr-2025-planning-et-inscriptions.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140348/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/pyconfr-2025-planning-et-inscriptions#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>grewn0uille,Ysabeau  🧶</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115253645040021529" />
        <id>https://mamot.fr/@AFPy/115253645040021529</id>
        <updated>2025-09-23T13:37:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>🔴 En direct à 15h30 : L'émission Libre à vous parlera de Python.</p><p><a href="https://www.libreavous.org/" rel="nofollow noopener" target="_blank"><span class="invisible">https://www.</span><span class="">libreavous.org/</span><span class="invisible"></span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Jeudi Programmation de l’ALDIL le 25 septembre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-25-septembre/2763" />
        <id>https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-25-septembre/2763</id>
        <updated>2025-09-23T11:16:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>L’ALDIL reprend ses ateliers d’initiations à la programmation ce jeudi, et pour cette première session, il y a du Python au programme.</p>
<p>Ça commence à 19h et ça se passe à la Maison pour tous / Salle des Rancy.</p>
<p>Plus d’informations <a href="https://www.aldil.org/events/jeudi-programmation-5/">sur leur site</a>.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-25-septembre/2763">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Summer 2025 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2025" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2025</id>
        <updated>2025-09-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
<li>Bronze tier sponsoring for the <a href="https://pycon.fr/2025">PyConFR</a> convention.</li>
</ul>
<h2><a href="https://magic-wormhole.readthedocs.io">Magic-Wormhole</a></h2>
<p><em>Get files from one computer to another, safely</em></p>
<ul>
<li><a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/56">Remove warnings about invalid escape sequence in strings</a></li>
<li>Replace formatted strings to f-strings for <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/57">the mailbox server</a> and <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/57">the relay server</a></li>
<li><a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/56">Git ignores files generated when the tests run</a></li>
<li>Update syntax to 3.9+ Python versions, done with <a href="https://github.com/domdfcoding/pyupgrade-directories">pyupgrade-directories</a>, for the <a href="https://github.com/magic-wormhole/magic-wormhole/pull/658">client</a>, <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/58">the mailbox server</a> and <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/58">the relay server</a></li>
<li>Replace deprecated <code>pkg_resources.resource_string()</code> call by <code>importlib.resources.file()</code> for <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/59">the mailbox server</a> and <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/59">the relay server</a></li>
<li><a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/60">Set environment variable to fix a test</a> by having the same stdout output</li>
</ul>
<h2><a href="https://github.com/repos/authlib/authlib">authlib</a></h2>
<p><em>The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.</em></p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/791">Temporarily restore OAuth2Request body parameter</a></li>
<li><a href="https://github.com/authlib/authlib/pull/800">Fix id_token generation with EdDSA alg</a></li>
<li><a href="https://github.com/authlib/authlib/pull/802">Sign OIDC id_token  according to id_token_signed_response_alg client metadata</a></li>
<li><a href="https://github.com/authlib/authlib/pull/803">Add diff-cover check in GHA</a></li>
<li><a href="https://github.com/authlib/authlib/pull/804">Move from pre-commit to prek</a></li>
<li><a href="https://github.com/authlib/authlib/pull/805">Run GHA unit tests with uv</a></li>
<li><a href="https://github.com/authlib/authlib/pull/810">Fix <code>InsecureTransportError</code> raising</a></li>
<li><a href="https://github.com/authlib/authlib/pull/811">Add conventional-commits pre-commit hook</a></li>
<li><a href="https://github.com/authlib/authlib/pull/812">Fix response_mode=form_post with Starlette client</a></li>
<li><a href="https://github.com/authlib/authlib/pull/813">Migrate tests to pytest paradigm</a></li>
<li><a href="https://github.com/authlib/authlib/pull/824">Use explicit *.test urls in unit tests</a></li>
<li><a href="https://github.com/authlib/authlib/pull/825">Add a <code>request</code> param to RFC7591 <code>generate_client_info</code> and <code>generate_client_secret</code> methods</a></li>
</ul>
<h2><a href="https://github.com/repos/pytest-dev/pytest-iam">pytest-iam</a></h2>
<p><em>A lightweight and fully functional OAuth2 / OpenID Connect (OIDC) / SCIM server to be used in test suites.</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-iam/pull/6">Fix fake_users and fake_groups exceptions</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Pythonically build SCIM requests and parse SCIM responses</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/31">Support for PATCH operations</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/32">Allow testing resources with multiple extensions</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/96">Ensure <code>PatchOp.path</code> is set for <code>remove</code> operations</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/97">Implement proper path validation for SearchRequest attributes</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/98">Implement PatchOp validation checks</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/100">Implement PatchOp.patch</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/101">Ignore invalid attributes and excluded_attributes on serialization</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/102">Don't normalize fields typed with <code>Any</code></a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/106">Allow non canonical values for Enums</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/107">Only allow one primary complex attribute value to be true</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/109">Explicit ComplexAttribute sub-attributes</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-server">scim2-server</a></h2>
<p><em>Lightweight SCIM2 server prototype</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-server/pull/10">Fix an error happening when PUT-ing an extension field to an instance</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/11">Fix behavior when patch removes null uneditable fields</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/12">Fix extension root patching</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>SCIM RFCs server compliance checker</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/31">Implement PATCH checks</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/32">Implement check filtering</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/33">Implement a resource manager to take care of garbages objects</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/35">Implement additional tests on the core resources</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/40">Handle empty response of PATCH operations</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/42">Correctly handle value generation in sub-attributes</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;été 2025</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2025" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2025</id>
        <updated>2025-09-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
<li>Soutien « bronze » à la convention <a href="https://pycon.fr/2025">PyConFR</a>.</li>
</ul>
<h2><a href="https://magic-wormhole.readthedocs.io">Magic-Wormhole</a></h2>
<p><em>Obtenir des fichiers d'un ordinateur à l'autre, en toute sécurité</em></p>
<ul>
<li><a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/56">Suppression de warnings sur des échappements dans des chaînes de caractères</a></li>
<li>Remplacement de formatage de chaînes de caractères en f-strings sur <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/57">le serveur boîte aux lettres</a> et <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/57">le serveur relai</a></li>
<li><a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/56">Fichiers générés par les tests ignorés par git</a></li>
<li>Utilisation de la syntaxe disponible sur les versions de Python 3.9+, réalisée grâce à <a href="https://github.com/domdfcoding/pyupgrade-directories">pyupgrade-directories</a>, pour le <a href="https://github.com/magic-wormhole/magic-wormhole/pull/658">client</a>, <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/58">le serveur boîte aux lettres</a> et <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/58">le serveur relai</a></li>
<li>Remplacement de l'appel <code>pkg_resources.resource_string()</code> obsolète par <code>importlib.resources.file()</code> pour <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/59">le serveur boîte aux lettres</a> et <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/59">le serveur relai</a></li>
<li><a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/60">Ajout d'une variable d'environnement pour corriger un test</a> en ayant la même sortie standard</li>
</ul>
<h2><a href="https://github.com/repos/authlib/authlib">authlib</a></h2>
<p><em>La bibliothèque Python ultime pour construire des clients et serveurs OAuth, OpenID Connect. JWS, JWE, JWK, JWA, JWT inclus.</em></p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/791">Restauration temporaire du paramètre body OAuth2Request</a></li>
<li><a href="https://github.com/authlib/authlib/pull/800">Correction de la génération d'id_token avec l'algorithme EdDSA</a></li>
<li><a href="https://github.com/authlib/authlib/pull/802">Signature des id_token OIDC selon les métadonnées client id_token_signed_response_alg</a></li>
<li><a href="https://github.com/authlib/authlib/pull/803">Ajout de la vérification diff-cover dans GHA</a></li>
<li><a href="https://github.com/authlib/authlib/pull/804">Migration de pre-commit vers prek</a></li>
<li><a href="https://github.com/authlib/authlib/pull/805">Exécution des tests unitaires GHA avec uv</a></li>
<li><a href="https://github.com/authlib/authlib/pull/810">Correction du déclenchement d'<code>InsecureTransportError</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/811">Ajout du hook pre-commit conventional-commits</a></li>
<li><a href="https://github.com/authlib/authlib/pull/812">Correction de response_mode=form_post avec le client Starlette</a></li>
<li><a href="https://github.com/authlib/authlib/pull/813">Migration des tests vers le paradigme pytest</a></li>
<li><a href="https://github.com/authlib/authlib/pull/824">Utilisation d'URLs *.test explicites dans les tests unitaires</a></li>
<li><a href="https://github.com/authlib/authlib/pull/825">Ajout d'un paramètre <code>request</code> aux méthodes RFC7591 <code>generate_client_info</code> et <code>generate_client_secret</code></a></li>
</ul>
<h2><a href="https://github.com/repos/pytest-dev/pytest-iam">pytest-iam</a></h2>
<p><em>Un serveur OAuth2 / OpenID Connect (OIDC) / SCIM léger et entièrement fonctionnel à utiliser dans les suites de tests.</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-iam/pull/6">Correction des exceptions fake_users et fake_groups</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Construire des requêtes SCIM et analyser les réponses SCIM de manière pythonique</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/31">Support des opérations PATCH</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/32">Support d'extensions multiples pour les ressources</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/96">Validation que <code>PatchOp.path</code> est défini pour les opérations <code>remove</code></a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/97">Validation des chemins pour les attributs SearchRequest</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/98">Validations sur PatchOp</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/100">Validatinos sur PatchOp.patch</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/101">Ignorance des attributs invalides et excluded_attributes lors de la sérialisation</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/102">Les champs typés avec <code>Any</code> ne sont pas normalisés</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/106">Les valeurs non canoniques sont autorisées pour les Enums</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/107">Une seule valeur d'attribut complexe primaire ne peut être vraie</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/109">Sous-attributs ComplexAttribute explicites</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-server">scim2-server</a></h2>
<p><em>Prototype de serveur SCIM2 léger</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-server/pull/10">Correction d'une erreur survenant lors du PUT d'un champ d'extension vers une instance</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/11">Correction du comportement quand patch supprime des champs null non-éditables</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/12">Correction du patching racine d'extension</a></li>
</ul>
<h2><a href="https://github.com/repos/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>Vérificateur de conformité serveur aux RFC SCIM</em></p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/31">Implémentation des vérifications PATCH</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/32">Implémentation du filtrage des vérifications</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/33">Implémentation d'un gestionnaire de ressources pour gérer les objets déchets</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/35">Implémentation de tests supplémentaires sur les ressources de base</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/40">Gestion des réponses vides des opérations PATCH</a></li>
<li><a href="https://github.com/python-scim/scim2-tester/pull/42">Gestion correcte de la génération de valeurs dans les sous-attributs</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Renouvellement du Comité Directeur</title>
        <link href="https://discuss.afpy.org/t/renouvellement-du-comite-directeur/2760" />
        <id>https://discuss.afpy.org/t/renouvellement-du-comite-directeur/2760</id>
        <updated>2025-09-19T15:50:40Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>La PyConFR approche, et donc la traditionnelle assemblée générale de l’AFPy avec le renouvellement du Comité Directeur !</p>
<p>Le Comité Directeur est composé de 9 personnes, actuellement : <a class="mention" href="https://discuss.afpy.org/u/debnet">@debnet</a>, <a class="mention" href="https://discuss.afpy.org/u/entwanne">@entwanne</a>, <a class="mention" href="https://discuss.afpy.org/u/reinula">@ReiNula</a>, <a class="mention" href="https://discuss.afpy.org/u/pierre.bousquie">@pierre.bousquie</a>, <a class="mention" href="https://discuss.afpy.org/u/mindiell">@Mindiell</a>, <a class="mention" href="https://discuss.afpy.org/u/tut-tuuut">@tut-tuuut</a>, <a class="mention" href="https://discuss.afpy.org/u/chadys">@Chadys</a>, <a class="mention" href="https://discuss.afpy.org/u/captainkro">@CaptainKro</a> et moi-même. Lors de chaque assemblée générale, un tiers du comité est renouvelé.</p>
<p>Le Comité Directeur est l’organe qui administre l’association au quotidien et organise la PyConFR.</p>
<p>Si vous avez envie de participer à animer la communauté Python et à organiser l’édition 2026 de la PyConFR, <strong>pourquoi pas rejoindre le Comité Directeur</strong> ? <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=14" title=":slight_smile:" width="20"/></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-11648-comment-a-se-passe-lassemble-gnrale-1" name="p-11648-comment-a-se-passe-lassemble-gnrale-1"></a>Comment ça se passe à l’assemblée générale ?</h2>
<p>Pour vous présenter, vous devez être membre de l’association (n’oubliez pas <a href="https://www.helloasso.com/associations/afpy/adhesions/adhesion-2025-a-l-afpy">votre adhésion</a>).<br/>
Les personnes intéressées pour rejoindre le comité se présentent, puis un vote a lieu.</p>
<p>Les personnes élues rejoignent alors le comité, qui propose alors un·e Président·e. Cette proposition est aussi soumise au vote de l’assemblée (n’oubliez pas <a href="https://www.helloasso.com/associations/afpy/adhesions/adhesion-2025-a-l-afpy">votre adhésion</a>).</p>
<p>Les différents autres postes du bureau sont attribués lors de la réunion du comité après l’assemblée.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-11648-comment-a-se-passe-au-comit-directeur-2" name="p-11648-comment-a-se-passe-au-comit-directeur-2"></a>Comment ça se passe au Comité Directeur ?</h2>
<p>Le comité se réunit une fois par mois en visio pour traiter les différents sujets.</p>
<p>Certains postes ont des tâches spécifiques :</p>
<ul>
<li>Le·la président·e dirige l’association au niveau global et suit l’ensemble des sujets.</li>
<li>Le·la trésorier·e gère l’argent de l’association, répond aux demandes de bourses concernant la PyConFR et édite les factures.</li>
<li>Le·la secrétaire s’occupe de la prise de notes lors des réunions, de la publication des compte-rendus / dépôt des documents auprès de la préfecture et de l’envoi des lettres d’invitation pour les demandes de visa pour la PyConFR.</li>
</ul>
<p>Chacun de ses postes est complété par un·e adjoint·e qui le supplée en cas d’absence.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-11648-a-mintresse-grave-de-rejoindre-3" name="p-11648-a-mintresse-grave-de-rejoindre-3"></a>Ça m’intéresse grave de rejoindre</h2>
<p>Si vous êtes intéressé·es pour rejoindre le comité, vous pouvez participer à une des prochaines réunions pour voir comment ça se passe. Elles sont le 9 et 21 octobre.</p>
<p>Si vous voulez savoir ce qui se raconte en réunion, tous les documents de gestion de l’association sont disponibles sur le dépôt Gitea <a href="https://git.afpy.org/AFPy/gestion">AFPy/gestion: Documents administratifs de l’AFPy. - La forge de l’AFPy</a>.</p>
<p>Si vous avez des questions sur le Comité Directeur, son fonctionnement etc, n’hésitez pas à les poser !</p>
<p><img alt="afpy-we_want_u" height="375" src="https://discuss.afpy.org/uploads/default/original/2X/1/15097f6a84a42b3744e86cf2305ba0e172dbf968.svg" width="338"/></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/renouvellement-du-comite-directeur/2760">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Réunion du comité directeur 09/10/2025 20h30 spéciale PyConFR</title>
        <link href="https://discuss.afpy.org/t/reunion-du-comite-directeur-09-10-2025-20h30-speciale-pyconfr/2756" />
        <id>https://discuss.afpy.org/t/reunion-du-comite-directeur-09-10-2025-20h30-speciale-pyconfr/2756</id>
        <updated>2025-09-16T21:09:48Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/reunion-du-comite-directeur-09-10-2025-20h30-speciale-pyconfr/2756/1">Réunion du comité directeur spéciale PyConFR</a></p>
<p>2025-10-09 20:30 (Europe/Paris)</p>
</div>
<p><small>3 messages - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/reunion-du-comite-directeur-09-10-2025-20h30-speciale-pyconfr/2756">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115214400099919194" />
        <id>https://mamot.fr/@AFPy/115214400099919194</id>
        <updated>2025-09-16T15:17:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Vous avez désormais la possibilité de participer à une visite guidé de Lyon le jeudi soir et le vendredi soir de la PyconFR au prix de 20€.</p><p>Vous pouvez vous inscrire au même endroit que pour la PyconFR sur <a href="https://www.helloasso.com/associations/afpy/evenements/pyconfr-2025" rel="nofollow noopener" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">helloasso.com/associations/afp</span><span class="invisible">y/evenements/pyconfr-2025</span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 25 septembre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-25-septembre/2752" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-25-septembre/2752</id>
        <updated>2025-09-15T09:52:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Le prochain meetup sur Lyon a lieu le jeudi 25 septembre à 19h, dans les locaux de GenyMobile (métro Saxe-Gambetta).</p>
<p>Pour ce meetup de rentrée, Raphaël nous parlera de la migration de différents outils web au sein du projet Mercurial <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=14" title=":snake:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-25-septembre/2752/1">Taxidermie 2.0 : quittez vos vieux outils web sans perdre vos données</a></p>
<p>2025-09-25 19:00 (Europe/Paris) → 2025-09-25 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-25-septembre/2752">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Chapitre 2024</title>
        <link href="https://yaal.coop/blog/chapitre-2024" />
        <id>https://yaal.coop/blog/chapitre-2024</id>
        <updated>2025-09-14T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Chapitre 2024 - Réseau, recrutement et parentalité</h1>
<h2>Introduction</h2>
<p>Bienvenue dans ce bilan de l'année 2024 de Yaal Coop !
Comme chaque année, nous tentons de vous raconter notre année en évènements, en (bonnes) pratiques (de l'ESS), en projets et en chiffres. Il s'agit d'une retranscription, un poil re-travaillée, de notre rapport de gestion annuel.</p>
<p>Dans l'introduction du <a href="https://yaal.coop/blog/chapitre-2023">Chapitre 2023</a>, on écrivait "Yaal Coop recrute !". Eh ben... Yaal Coop a recruté !</p>
<p>Notre AGO de clôture de l'année 2024 s'est déroulée le 26 mai 2025, et en voilà le rapport de gestion :</p>
<hr/>
<h2>Bonnes pratiques ESS de la coopérative</h2>
<h3>Gouvernance démocratique :</h3>
<p>Conformément à nos statuts et à nos pratiques internes, Yaal Coop maintient et met à jour sa gouvernance en suivant les principes de l’holacratie, adaptés à la taille de la structure.</p>
<p>Les réunions de revue de notre gouvernance, servant à confirmer, modifier, supprimer ou ajouter des rôles de gestion se tiennent toujours de façon trimestrielle.</p>
<p>Cette année, le rôle d’orchestration de la stratégie de communication de Yaal Coop a fait son retour, suite à un besoin ressenti pour la coopérative de se faire connaître en ligne et dans nos réseaux.</p>
<p>Les rotations des rôles ont lieu lors de leur arrivée à échéance, au cours des réunions hebdomadaires.</p>
<p><strong>Les rôles tournants définis actuellement sont les suivants :</strong></p>
<ul>
<li>💌 Facteur·rice (qui relève le courrier entrant de nos différents boîtes mail et postale communes) - 2 semaines</li>
<li>📟 Sentinelle (qui surveille les alertes levées par notre système de monitoring technique) - 2 semaines</li>
<li>✒️ Secrétaire (qui programme et prend des notes de nos réunions régulières) - 3 mois</li>
<li>🗨️ Facilitateur·rice (qui anime nos réunions régulières) - 3 mois</li>
<li>🏦 Billetterie (qui fait la paie) - 3 mois</li>
<li>🍲 Ticket-Restaurateur·rice (qui gère la distribution des tickets restaurants) - 3 mois</li>
<li>📜 Marteau de la Justice (qui s'assure que Yaal Coop respecte ses obligations légales) - 6 mois</li>
<li>🕊️ Libre Entrepriseur·euse (qui représente Yaal Coop au sein du réseau Libre-entreprise) - 6 mois</li>
<li>😽 Chaton·ne (qui représente Yaal Coop au sein du collectif CHATONS) - 1 an</li>
<li>🪙 Argentier·e (qui suit et budgétise la trésorerie) - 1 an suivi de 1 an en backup</li>
<li>🎊 Grand·e Coopérateur·rice (qui porte le mandat de Président·e, organise les Assemblées Générales et le sociétariat et s'assure que les formalités administratives sont traitées) - 2 ans</li>
<li>🎙️ Barde (qui porte la stratégie de communication de Yaal Coop) – 3 mois</li>
</ul>
<p><strong>Ils sont complétés par 4 rôles permanents occupés par tous les salariés :</strong></p>
<ul>
<li>🚀 Responsable projet/prospect (qui est le référent d'un projet et le contact privilégié de ses éventuels clients)</li>
<li>🛠️ Producteur·rice (qui produit du travail de qualité et se forme sur son métier)</li>
<li>🎯 Chasseur·euse cueilleur·euse (qui s'occupe de la communication et du commerce)</li>
<li>👤 Salarié·e (qui remplit ses obligations de salariés)</li>
</ul>
<p>Tous ces rôles ont une liste de redevabilités associées qui évolue également en fonction des besoins et des constats/manques éventuels observés.</p>
<p>Nos réunions hebdomadaires de suivi de l'activité et les réunions trimestrielles de stratégie sur l'investissement réunissant les salarié·es sont toujours en place.</p>
<h3>Stratégie et organisation de Yaal Coop :</h3>
<p>La stratégie et l’organisation à court terme de Yaal Coop s’articulent autour des réunions hebdomadaires qui réunissent les salarié·es et les associé·es pour la revue des actions réalisées ou non lors de la semaine précédente, la revue des projets en cours, des rôles expirés, et des tensions à évoquer.</p>
<p>Au long terme, ce sont nos points de "Rétro d’investissement" qui structurent la stratégie globale de la coopérative : nous y révisons les objectifs du trimestre passé, notre gestion du temps, et y fixons de façon commune les objectifs du trimestre à suivre. Les salarié·es et les associé·es salarié·es y participent de concert.</p>
<h3>Egalité :</h3>
<p>Conformément à nos décisions collectives et aux statuts de Yaal Coop, les associé·es salarié·es sont à salaire égal.</p>
<h3>ESS :</h3>
<p>Yaal Coop favorise toujours les acteurs de l'économie sociale et solidaire en plus des missions de service public, et en particulier les coopératives, dans son choix de clients et de fournisseurs.
Nous n'avons pas souscrit de nouvelles parts de capital social mais nous possédons toujours celles de notre banque Crédit Coopératif (10 parts pour un montant de 152,50€), notre cabinet comptable Finacoop (1 part de 100€), notre cabinet de paie Assistea (1 part de 100€), et notre fournisseur téléphonique mobile et client Telecoop (1 part de 100€).</p>
<h3>Impact environnemental :</h3>
<p>Conformément à nos convictions, et comme les années précédentes, Yaal Coop a versé à l'ensemble de l'équipe salariée le forfait mobilité durable à hauteur de 700€ par an, pour maintenir et encourager l'utilisation de mobilités douces (le vélo principalement) dans les déplacements du domicile au lieu de travail.</p>
<p>Les abonnements aux transports en commun (train, réseau TBM) sont intégralement remboursés aux salarié·es.</p>
<p>Pour limiter son empreinte écologique, Yaal Coop a choisi d’investir dans un matériel de travail améliorable et réparable sur le long terme, notamment avec l’achat d’un ordinateur portable Framework.</p>
<p>Enfin la question du numérique soutenable est toujours une question d'intérêt pour la coopérative. Nous continuons de choisir soigneusement les projets sur lesquels nous travaillons pour éviter de contribuer à l'impact du numérique sur des projets que nous jugeons peu utiles voire contre-productifs.</p>
<p>De façon plus anecdotique, sur les logiciels que nous développons (tels que canaille), nous utilisons les outils d’audit à notre disposition pour travailler sur la légèreté des pages générées. Nous essayons notamment de suivre quelques référentiels de bonnes pratiques de conception et de développement :</p>
<p>• Le GR491
 • Le Référentiel général d’écoconception de services numériques (RGESN)
 • Les fiches de bonnes pratiques GreenIT</p>
<p>Afin de réduire les transferts réseau, nous prenons soin de réduire les tailles de nos images, de n’afficher que le contenu nécessaire sur des pages volontairement simples, de réduire la taille du code source que nous transférons. Nous visons des scores d’au moins 90 % ou B sur les outils que nous utilisons pour mesurer la performance de nos pages (tels que lighthouse ou ecoindex.fr).</p>
<h1>🟡</h1>
<h2>Réseaux</h2>
<p>Cette année, Yaal Coop maintient sa participation au sein du Collectif CHATONS, avec la solution d'hébergement, de messagerie et d'e-mail Nubla.</p>
<p>La coopérative participe à quelques réunions mensuelles du collectif au cours de l'année, s'exprime et vote lors des prises de décision qui animent le collectif, comme l’audit des candidats du collectif. Yaal Coop a également été représentée au Camp CHATONS, moment clé de la vie du collectif, lors de l’été 2024.</p>
<p>Yaal Coop maintient également sa participation dans le réseau Libre Entreprise, avec le partage de comptes-rendu mensuels résumant les projets de la coopérative, sa vie et son activité, avec la participation aux réunions mensuelles du réseau.</p>
<p>Yaal Coop est toujours adhérente du pôle de compétences régional en logiciels et technologies libres et open source NAOS.</p>
<h1>🟡</h1>
<h2>Favoriser l'utilisation et le développement de logiciels libres</h2>
<p>Même s'il ne s'agit pas d'une condition exclusive, la majeure partie de nos projets en 2023 a été réalisée sur du code libre, qu'il s'agisse de nos projets internes (Canaille, Nubla) ou de nos prestations (Portail RSE, PodEduc, B3Desk).</p>
<h3>Contributions de l'année à des logiciels libres</h3>
<p>Les contributions sont résumées chaque saison dans des articles de blog visibles sur notre <a href="https://yaal.coop/blog">site web</a>. Elles sont, soit limitées à quelques modifications ciblées sur des logiciels utilisés, soit des contributions au long cours sur quelques bibliothèques et outils spécifiques (en particulier autour de l'écosystème de Canaille).</p>
<h3>Participations</h3>
<p>En plus de nos contributions en développement et/ou design, nous avons décidé de contribuer financièrement à 2 projets libres sur Github que nous utilisons, à hauteur de 20 $/mois.</p>
<h1>🟡</h1>
<h2>Situation et activité de la Coopérative pendant l'année écoulée</h2>
<h3>Embauches :</h3>
<p>Après le départ d’Éloi au mois de Juin, il a été nécessaire d’échanger sur la stratégie de Yaal Coop ainsi que sur la répartition du travail dans les projets en cours et ceux à venir. Manquant notamment de disponibilités pour la réalisation des développements NLNet et de flexibilité sur notre avenir, nous avons décidé de lancer une phase de recrutement d’un·e développeur·euse python pour compléter notre équipe.</p>
<p>Après plus d’une dizaine d’entretiens en discussion et d’entretiens techniques, nous avons décidé de recruter deux développeurs junior, dont les profils sont complémentaires à nos yeux, Sébastien et Félix.</p>
<p>Ils ont rejoint notre équipe respectivement en septembre et en octobre, après une période de POEI (préparation opérationnelle à l'emploi individuelle) durant l’été pour Sébastien.</p>
<h3>Evolution de l’activité :</h3>
<p><strong>Projets et revenus :</strong> En 2024, la majorité des revenus de Yaal Coop sont issus de la mission sur Portail RSE, avec 3 personnes sur le projet en début d’année, puis 2 en milieu d’année, et Stéphane sur la fin de l’année. Le projet est toujours en cours et Camille a été réintégrée à l’équipe à l’issue de son congé maternité, début 2025.</p>
<p>Toutefois, nous aimerions être moins dépendants d’un seul projet pour la pérennité de la coopérative, d’autant que l’initiative Beta Gouv et les projets qui en dépendent sont aussi dépendants de la politique intérieure changeante du pays.</p>
<p><strong>Activité sociale :</strong> Éloi quitte Yaal Coop le 20 juin 2024, un départ temporaire choisi pour des raisons personnelles, et avec un retour prévu dans l’année suivante.</p>
<p>L’été suivant le départ d’Éloi est rythmé par la recherche d’un·e développeur·euse pour compléter l’équipe. Sébastien, l’un des développeurs retenu par la coopérative, est formé par Yaal Coop en POEI pendant l’été.</p>
<p>Camille est en congé parental à partir de septembre 2024, et c’est également en septembre 2024 que Sébastien rejoint l’équipe de Yaal Coop, en CDI.</p>
<p>Début octobre 2024, Félix rejoint à son tour l’équipe, en CDI également.</p>
<p><strong>Activité financière :</strong> Le chiffre d’affaires 2024 s’élève à 235 866 €, il est de 26 % inférieur à celui de 2023.</p>
<p>La baisse d’activité s’explique par la réduction progressive de l’effectif sur le projet Portail RSE notammment, ainsi que par le départ d’Éloi en milieu d’année, réduisant le nombre de développeur·euses senior disponibles sur des projets apportant des revenus à la Coop.</p>
<p>Elle s’explique également par la réalisation de moins de développements que prévu sur certains de nos projets.</p>
<p>En parallèle, sur la fin d’année, les coûts augmentent pour la coopérative avec le recrutement de deux développeurs junior en CDI.</p>
<p>Ainsi, le résultat de 2024 de Yaal Coop est de 14 858 €.</p>
<p>Côté trésorerie, Yaal Coop est à 144,1k€ fin 2024, après un remboursement de compte courant de 100k€ auquel s’additionne les salaires, qui représentent la majorité de nos dépenses, s’élevant à 190k€ sur l’année.</p>
<h1>🟡</h1>
<h2>Evolution des affaires et projets en cours</h2>
<h3>Projets réalisés ou en cours en 2024 :</h3>
<h4><a href="https://canaille.readthedocs.io">Canaille</a></h4>
<p>Canaille est notre logiciel libre de gestion d'identité et d'autorisations développé en interne.</p>
<p>Un nouveau financement de 45 500€ nous a été accordé pour le développement de Canaille de la part de la fondation européenne NLNet. Les développements ont été réalisés en partie début 2024, et l’autre partie fin 2024 et début 2025, permettant à Yaal Coop de débloquer 37 000€ sur les 45 500 prévus initialement.</p>
<p>Les développements en 2024 ont été réalisés par Éloi en début d’année, et par Brunélie,</p>
<p>Félix et Sébastien en fin 2024 et début 2025.</p>
<h4><a href="https://portail-rse.beta.gouv.fr">Portail RSE</a></h4>
<p>Camille et Stéphane poursuivent le développement de la plateforme Portail RSE (anciennement Projet IMPACT), Start-up d'État faisant partie du programme beta.gouv et pilotée par la Direction Générale des Entreprises.</p>
<p>Brunélie quitte le projet fin avril, et Camille est en congé maternité à partir de</p>
<p>Septembre, réduisant donc la part de revenus liés à ce projet pour Yaal Coop.</p>
<p>La plateforme se concentre sur la pédagogie et l’aide à la saisie du rapport répondant à la réglementation CSRD pour les entreprises.</p>
<h4><a href="https://podeduc.apps.education.fr">Podeduc</a></h4>
<p>PodEduc est un projet d’hébergement et de montage de vidéos à destination de l’éducation nationale.</p>
<h4><a href="https://github.com/numerique-gouv/b3desk">B3Desk</a></h4>
<p>B3Desk est un projet de gestion des accès aux plateformes de visioconférences utilisées par l’éducation nationale.</p>
<h4><a href="https://nubla.fr">Nubla</a></h4>
<p>Nubla est notre service d'e-mail, cloud et messagerie à destination des particuliers et professionnels.</p>
<p>Cette année, nous n’avons pas eu beaucoup de temps à accorder au développement de Nubla. Nous avons maintenu et renouvelé le service pour nos clients actuels.</p>
<h4><a href="https://telecoop.fr">Telecoop</a></h4>
<p>Yaal Coop développe un backoffice de gestion des lignes téléphoniques et des factures pour Télécoop. Un contrat cadre a été signé, provisionnant quelques jours par mois pour le développement régulier du projet, par Loan.</p>
<h1>🟡</h1>
<h2>Quels risques et incertitudes ?</h2>
<ul>
<li>L’un des principaux risques pour l’activité de Yaal Coop actuellement est la proportion de revenus liée à un seul client, Portail RSE, dont la pérennité dépend de politiques publiques.</li>
<li>De façon récurrente, la coopérative manque de compétences en commerce et en communication : Trouver de nouveaux clients est complexe, et il est donc aujourd’hui difficile de dire quels seront nos revenus et nos missions futures.</li>
</ul>
<p>En réponse à cette problématique, Yaal Coop augmente sa présence au sein de ses réseaux et rejoint des groupements d’entreprise pour répondre à des marchés publics.</p>
<ul>
<li>La disponibilité des développeur·euses senior est limitée, et rend complexe l’embarquement des développeur·euses junior sur des projets existants et sur le lancement de nouveaux projets.</li>
</ul>
<h1>🟡</h1>
<h2>Ce qu'il s'est passé entre la clôture de l'année et l'AG :</h2>
<p>Début 2025, Loan est en congé paternité. Fin janvier 2025, l’équipe est de nouveau au complet.</p>
<p>Les derniers développements sur Canaille couverts par le financement NLNet sont réalisés en début d’année, et la dernière demande de financements acceptée début mai.</p>
<p>Yaal Coop a accueilli les journées Libre Entreprise au printemps 2025.</p>
<h1>🟡</h1>
<h2>2025, et après ?</h2>
<p>Yaal Coop a pour projet courant 2025 l’intégration à La Zone, union de coopératives dont l’objectif est la réponse à des marchés publics, notamment les marchés interministériels d’attributaires comme beta.gouv.</p>
<p>La coopérative répond également à différents marchés publics en cours, en groupement avec d’autres coopératives.</p>
<p>Les projets en cours sont poursuivis.</p>
<p>Yaal Coop se regroupe avec d’autres acteurs du logiciel libre et de la fourniture de services cloud, IndieHosters, OpenSource Politics et Le Bureau coop pour proposer La Suite.coop, une suite d’outils numériques libres pour les organisations collaboratives.</p>
<p>Nous n’excluons pas de faire de nouveau appel à la fondation NLNet pour de futurs développements sur Canaille.</p>
<hr/>
<h2>Une conclusion ?</h2>
<p>Et voilà, c'est le clap de fin pour ce résumé de notre année 2024, et un extrait de ce qu'il s'est passé pour nous début 2025.</p>
<p>On espère que la lecture vous a plu, ou au moins un petit peu informé, et on se retrouve l'an prochain.</p>
<p>Brunélie, pour Yaal Coop</p>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Canaille obtient la certification OpenID Connect</title>
        <link href="https://yaal.coop/blog/canaille-oidc-certification" />
        <id>https://yaal.coop/blog/canaille-oidc-certification</id>
        <updated>2025-09-11T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Depuis sa version 0.0.82, <a href="https://canaille.readthedocs.io">Canaille</a> a obtenu la certification OpenID Connect par la fondation OpenID pour les profils <em>Basic</em> et <em>Dynamic</em>.
Canaille est désormais listée parmi <a href="https://openid.net/developers/certified-openid-connect-implementations/">les implémentations officielles</a>.
Ce développement fait partie de notre <a href="https://yaal.coop/blog/canaille-nlnet-pytest-iam">subvention par la fondation NLNet</a>, et a nécessité que nous améliorions la bibliothèque logicielle <a href="https://github.com/authlib/authlib">Authlib</a> sur laquelle Canaille s'appuie.</p>
<p><a href="https://openid.net/developers/certified-openid-connect-implementations/"><img alt="Canaille OIDC certification" src="https://yaal.coop/media/blog/articles/canaille-oidc-certification.png"/></a></p>
<p>Il ne nous reste <a href="https://gitlab.com/yaal/canaille/-/milestones">plus grand chose</a> avant de quitter la version Alpha !</p>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Canaille obtains the OpenID Connect certification</title>
        <link href="https://yaal.coop/blog/en/canaille-oidc-certification" />
        <id>https://yaal.coop/blog/en/canaille-oidc-certification</id>
        <updated>2025-09-11T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Since version 0.0.82, <a href="https://canaille.readthedocs.io">Canaille</a> obtained the OpenID Connect certification by the OpenID for the <em>Basic</em> and <em>Dynamic</em> profiles
It is now listed among the <a href="https://openid.net/developers/certified-openid-connect-implementations/">official implementations</a>.</p>
<p>This development is part of our <a href="https://yaal.coop/blog/en/canaille-nlnet-pytest-iam">grant by the NLNet foundation</a>,
and required that we improve the <a href="https://github.com/authlib/authlib">Authlib</a> library on which Canaille relies upon.</p>
<p><a href="https://openid.net/developers/certified-openid-connect-implementations/"><img alt="Canaille OIDC certification" src="https://yaal.coop/media/blog/articles/canaille-oidc-certification.png"/></a></p>
<p>There is <a href="https://gitlab.com/yaal/canaille/-/milestones">only a few things to achieve</a> before we can leave the Alpha versions!</p>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris - Meetup Django le 30 septembre</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-30-septembre/2750" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-django-le-30-septembre/2750</id>
        <updated>2025-09-11T22:39:37Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Meetup Django le <strong>30 septembre 2025</strong> dans les locaux d’<strong>Octopus Energy/Kraken Tech</strong> 87 Rue de Richelieu, <strong>Paris</strong>.</p>
<p>L’occasion de se retrouver et d’en apprendre plus sur:</p>
<ul>
<li><strong>Le futur de Django</strong>, Thibaud Colas (Français)</li>
<li><strong>La Suite Numérique : quand Django propulse une bureautique européenne, libre et souveraine</strong>, Samuel Paccoud (Français)</li>
</ul>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-30-septembre/2750/1">Django Paris Meetup</a></p>
<p>2025-09-30 19:00 (Europe/Paris) → 2025-09-30 22:00 (Europe/Paris)</p>
</div>
<p>Rappel des informations de l’événement sur <a href="https://www.meetup.com/django-paris/events/310269324/?utm_medium=referral&amp;utm_campaign=share-btn_savedevents_share_modal&amp;utm_source=link&amp;utm_version=v2" rel="noopener nofollow ugc">meetup.com</a>.</p>
<p>Tres bonne journée à toute/s !</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-30-septembre/2750">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>sabderemane</name>
        </author>
    </entry>
    <entry>
        <title>{Feel~Free} How to Call QuickBooks®️ Desktop™️ Support™️ Number – A Complete Guide</title>
        <link href="https://discuss.afpy.org/t/feel-free-how-to-call-quickbooks-desktop-support-number-a-complete-guide/2748" />
        <id>https://discuss.afpy.org/t/feel-free-how-to-call-quickbooks-desktop-support-number-a-complete-guide/2748</id>
        <updated>2025-09-11T14:26:43Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Reaching a live representative 1-855-838-5970 or 1 ⤷ 855 ⤷ 838 ⤷ 5977 at QuickBooks Desktop Support can make all the difference. You can call 1-855-838-5970 or 1 ⤷ 855 ⤷ 838 ⤷ 5977 or 1-800-QuickBooks (US/OTA) to speak directly with an agent—available 24/7. Whether it’s booking issues, cancellations, refunds, or technical +1-855-838-5970 problems, this guide walks you through every 1-855-838-5970 or 1 ⤷ 855 ⤷ 838 ⤷ 5977 contact method available so your concerns are handled quickly and easily.</p>
<p>The main QuickBooks Desktop Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with QuickBooks Desktop setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Payroll support number. QuickBooks’ Desktop main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>The main QuickBooks Enterprise Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Desktop setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Online support number. QuickBooks’ main line is or 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>How Do I Contact QuickBooks Support by Phone?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Error support number. QuickBooks’ main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>The main QuickBooks Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Desktop setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>How do I contact QuickBooks Desktop Support Number?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Desktop support number. QuickBooks’ Desktop main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>The main QuickBooks Desktop Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Desktop setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>How do I contact QuickBooks Desktop Support Number?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Desktop support number. QuickBooks’ main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>Contact QuickBooks Desktop support easily by calling 1⇀855⇀838⇀5977 or +1⇀855⇀838⇀5970. Their team can help you with data backups, syncing issues, report generation, and more. Whether you’re new to QuickBooks or need advanced troubleshooting, this number connects you directly to a knowledgeable specialist. Help is just one phone call away.</p>
<p>The main QuickBooks Desktop Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Desktop setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>How do I contact QuickBooks Error Support Number?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Error support number. QuickBooks’ main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>? Calling QuickBooks Error Support at 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970. The quickest way to reach a live agent is by calling the QuickBooks Error support phone number: 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970. Our system will guide you through options such as QuickBooks Online, Desktop, or Desktop.</p>
<p>How do I contact QuickBooks Premier Support Number?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Premier support number. QuickBooks’ Premier main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>The main QuickBooks Premier Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Premier setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>How do I contact QuickBooks Online Support Number?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks online support number. QuickBooks’ Online main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>The main QuickBooks Online Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Desktop setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>How do I contact QuickBooks Enterprise Support Number?</p>
<p>The simplest way to speak with a live person is by calling our QuickBooks Enterprise support number. QuickBooks’ Enterprise main line is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970 [US Support] (Live Agent). When you call, you’ll be connected to a live representative who can assist with billing, account management, software support, and more.</p>
<p>The main QuickBooks Enterprise Support number is 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970, where you can reach a live representative 24/7. Whether you’re dealing with Enterprise setup, login issues, subscription billing, or technical errors, speaking with a real person can make all the difference. You can also use QuickBooks live chat or email support for added flexibility. This guide walks you through how to contact QuickBooks support efficiently plus helpful tips to reduce wait times and get your issues resolved faster.</p>
<p>? Calling QuickBooks Desktop Support</p>
<p>The quickest way to reach a live agent is by calling the QuickBooks support phone number: 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970. Our system will guide you through options such as QuickBooks Online, Desktop, or Desktop.</p>
<p>Main QuickBooks Support</p>
<p>? 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970</p>
<p>QuickBooks Desktop Support</p>
<p>? 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970</p>
<p>QuickBooks Online Desktop Support</p>
<p>? 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970</p>
<p>QuickBooks Time Support</p>
<p>? 1⇢(855)⇢838⇢5977 or+1⇀855⇀838⇀5970</p>
<p>How to Contact QuickBooks Support By Phone</p>
<p>To talk with a QuickBooks representative, simply call 1-855-838-5970 or 1 ⤷ 855 ⤷ 838 ⤷ 5977 and follow the prompts. Whether it’s a billing inquiry, account recovery, or technical issue, our team will help resolve your issues.</p>
<p>Speak to Someone at QuickBooks Support</p>
<p>If you need detailed help with your QuickBooks account, don’t hesitate to call 1-855-838-5970 or 1 ⤷ 855 ⤷ 838 ⤷ 5977. Our team is ready to assist you with the most common support topics:</p>
<p>People Also Search For:</p>
<p>Call to Live Agent at QuickBooks</p>
<p>Contact QuickBooks Support</p>
<p>Speak to QuickBooks Representative</p>
<p>QuickBooks Help Desk</p>
<p>QuickBooks Live Chat Support</p>
<p>QuickBooks Customer Service Number</p>
<p>QuickBooks Help Center</p>
<p>Contact QuickBooks Tech Support</p>
<p>Talk to QuickBooks Expert</p>
<p>QuickBooks Desktop Support Number</p>
<p>QuickBooks Desktop Support Number</p>
<p>QuickBooks Enterprise Support Number</p>
<p>QuickBooks Online Support Number</p>
<p>QuickBooks Desktop Help</p>
<p>QuickBooks Desktop Customer Service</p>
<p>QuickBooks Technical Support Number</p>
<p>QuickBooks Desktop Phone Number</p>
<p>QuickBooks Desktop Phone Number</p>
<p>Are you struggling with QuickBooks ™️CUSTOMER Support issues You Can Dial 1-855-838-5977 and +1-855-838-5977 that are slowing down your business operations? Don’t worry—our team is here to help! Call the QuickBooks®️™️ Number 1-855-838-5977 and +1-855-838-5977 to connect with certified experts who specialize in solving QuickBooks®️™️ challenges.</p>
<p>Whether you’re dealing with installation problems, complex codes, or issues related to Desktop, taxes, or inventory management, we provide comprehensive QuickBooks®️™️1-855-838-5970 and +1-855-838-5977 . Our experts are available to walk you through each step, ensuring you get back to smooth operations as quickly as possible.</p>
<p>Why You Should Call the QuickBooks®️™️ Number?</p>
<p>1-855-838-5977 and +1-855-838-5977 are your go-to QuickBooks®️™️ Numbers, offering a direct line to certified professionals. We provide solutions for a wide range of issues, including:</p>
<p>Setup Assistance: Need help configuring your QuickBooks®️™️? Our experts guide you through everything from initial setup to d configurations, ensuring you get the most out of your software.</p>
<p>Code Troubleshooting: Encountering QuickBooks®️™️ codes? Call 1-855-838-5977 and +1-855-838-5977, and we’ll help you troubleshoot and resolve any s, from installation failures to malfunctioning modules.</p>
<p>Tax Filing and Desktop Help: Struggling with Desktop tax filings or tax updates in QuickBooks®️™️? Our team ensures that your tax table is up-to-date and that your Desktop is calculated correctly. Dial 1-855-838-5977 and +1-855-838-5977 to resolve these issues quickly and stay compliant.</p>
<p>Inventory Management : Managing inventory can be complex. If you’re encountering issues with QuickBooks®️™️ Inventory Management, our experts will help streamline your processes, from setting up stock levels to resolving inventory discrepancies.</p>
<p>Get the Most Out of QuickBooks®️™️: How Our Helps You</p>
<p>When you call the QuickBooks®️™️ Number, 1-855-838-5977 and +1-855-838-5977, you gain access to expert advice and assistance with:</p>
<p>System Integration</p>
<p>Sync your QuickBooks®️™️ with other business management systems to automate workflows and reduce s. Our experts help with system integration to save time and increase efficiency.</p>
<p>Multi-User Setup</p>
<p>If you’re adding users to your QuickBooks®️™️ system, we’ll guide you through the multi-user setup process, ensuring everyone can access the right information without complications.</p>
<p>Custom Reports and Analytics</p>
<p>QuickBooks®️™️* offers powerful reporting features. Whether you need to generate financial reports, tax documents, or sales analytics, we’ll assist in customizing reports that fit your business needs. Dial 1-855-838-5977 and +1-855-838-5977 for step-by-step guidance.</p>
<p>Data Backup and Recovery</p>
<p>Protect your business data with secure backup and recovery solutions. In case of data loss, call the QuickBooks®️™️ Number at 1-855-838-5977 and +1-855-838-5977 for quick assistance in restoring your data.</p>
<p>Software Updates</p>
<p>Stay up-to-date with the latest QuickBooks®️™️ features. Call us at 1-855-838-5977 and +1-855-838-5977 for guidance on updating your system and keeping it compliant with the latest tax laws and business requirements.</p>
<p>Steps to Contact QuickBooks®️™️</p>
<p>When you dial 1-855-838-5977 and +1-855-838-5977, you’ll get immediate access to a QuickBooks®️™️ specialist. Here’s how we can help:</p>
<p>Explain Your Issue: Our experts will listen carefully to your issue to understand exactly what’s going wrong with your QuickBooks®️™️ system.</p>
<p>Provide a Solution: Based on your needs, we’ll offer a step-by-step solution that fits your business’s unique requirements.</p>
<p>Assist with Configuration: Whether it’s system configuration, module settings, or user permissions, we’ll walk you through each step to ensure everything is set up correctly.</p>
<p>Ongoing : Our team doesn’t just solve your immediate problems—we’re here for ongoing advice and .</p>
<p>Why Trust QuickBooks®️™️ Number</p>
<p>Certified Experts: The QuickBooks®️™️ Number provides access to trained and certified professionals with deep expertise in QuickBooks®️™️.</p>
<p>Comprehensive Solutions: Whether you’re dealing with a technical glitch, tax issue, or inventory problem, our team offers a comprehensive solution.</p>
<p>Quick Response Time: When you call 1-855-838-5977 and +1-855-838-5977, you can expect a fast response from a QuickBooks®️™️ expert who will guide you through the issue at hand.</p>
<p>Frequently Asked Questions (FAQs)</p>
<p>Q1: How can I get help with QuickBooks®️™️?</p>
<p>Call 1-855-838-5977 and +1-855-838-5977for QuickBooks®️™️ and connect with an expert who will assist you with troubleshooting, configuration, and much more.</p>
<p>Q2: What types of issues can QuickBooks®️™️ help with?</p>
<p>Our covers a wide range of topics, including Desktop setup, inventory management, code troubleshooting, tax filing, and multi-user configuration.</p>
<p>Q3: Is available 24/7?</p>
<p>Yes, 1-855-838-5977 and +1-855-838-5977 provide 24/7 for any QuickBooks®️™️ issues that arise, no matter the time of day.</p>
<p>Q4: Can I get help with QuickBooks®️™️ installation?</p>
<p>Absolutely! Call 1-855-838-5977 and +1-855-838-5977 for assistance with QuickBooks®️™️ installation and setup, and we’ll walk you through the entire process.</p>
<p>Q5: How can I resolve QuickBooks®️™️ codes?</p>
<p>When you encounter codes in QuickBooks®️™️, call 1-855-838-5977 and +1-855-838-5977 for troubleshooting and expert guidance on resolving any message you’re facing.</p>
<p>Final Thoughts</p>
<p>For any QuickBooks®️™️ issue—whether it’s installation s, tax filing problems, inventory management challenges, or report generation concerns—1-855-838-5977 and +1-855-838-5977 are your QuickBooks®️™️ Numbers to call. Our experts provide step-by-step guidance and fast, reliable solutions to get your business back on track. Don’t let technical issues slow you down—contact us today!</p>
<p>QuickBooks®️™️ Related Numbers</p>
<p>QuickBooks®️</p>
<p>QuickBooks®️ Service</p>
<p>QuickBooks®️ Support</p>
<p>QuickBooks®️ Desktop Help</p>
<p>QuickBooks®️ Tax Filing Assistance</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/feel-free-how-to-call-quickbooks-desktop-support-number-a-complete-guide/2748">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>aquamarineemeline</name>
        </author>
    </entry>
    <entry>
        <title>Entr’ouvert - Développeur·euse Python/Django - [Paris, Lyon, télétravail]</title>
        <link href="https://discuss.afpy.org/t/entr-ouvert-developpeur-euse-python-django-paris-lyon-teletravail/2745" />
        <id>https://discuss.afpy.org/t/entr-ouvert-developpeur-euse-python-django-paris-lyon-teletravail/2745</id>
        <updated>2025-09-08T11:05:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://www.entrouvert.com/" rel="noopener nofollow ugc">Entr’ouvert</a> est un éditeur de logiciels libres dont l’activité s’est développée autour de la gestion de la relation usager. Notre mission, c’est de simplifier les démarches des citoyens puis de les proposer en ligne… en ce moment cela a un certain succès.</p>
<p>Entr’ouvert est une SCOP fonctionnant depuis 2002 de manière démocratique, détenue intégralement et à parts égales par ses salarié·es et où chacun, en tant qu’associé·e, participe aux prises de décision. Et parce que nous ne faisons pas les choses à moitié, nous avons institué la stricte égalité salariale.</p>
<p>Nous sommes actuellement 29 : 13 développeuses·eurs, 13 fonctionnel·le·s, 2 administrateurs·rices systèmes, une responsable administratif et pratiquement aucun raton laveur.</p>
<p>Nous n’utilisons et ne produisons que des logiciels libres. Nous avons développé une relation de confiance avec nos clients, basée sur la qualité, l’importance accordée aux détails, le travail bien fait. Et cela ne nous empêche pas de rigoler, c’est même recommandé, l’esprit de sérieux étant un mauvais esprit. Au-delà des compétences professionnelles, nous recherchons des personnes qui sauront intégrer notre équipe et s’impliquer dans notre structure coopérative.</p>
<p><strong>Nous cherchons un·e développeur·euse</strong></p>
<ul>
<li>
<p>Vous connaissez bien Python et Django, vous possédez des connaissances basiques en HTML, CSS et Javascript.</p>
</li>
<li>
<p>Vous savez faire un git commit et un git push (sans -f).</p>
</li>
<li>
<p>Vous êtes à l’aise avec l’écriture de tests, unitaires ou fonctionnels.</p>
</li>
<li>
<p>On suit les recommandations PEP8, on aime le code propre et maintenable et on espère que vous aussi.</p>
</li>
<li>
<p>Vous savez exprimer une situation ou une solution à vos collègues et aux clients.</p>
</li>
<li>
<p>Vous appréciez la relation directe avec les client·e·s afin de bien cerner leurs demandes.</p>
</li>
<li>
<p>Vous savez gérer les priorités et aimez tenir vos échéances.</p>
</li>
<li>
<p><em>A priori</em> pour savoir faire tout cela, vous avez déjà quelques années d’expérience.</p>
</li>
<li>
<p>…. et au minimum une certaine sensibilité aux logiciels libres.</p>
</li>
</ul>
<h4><a class="anchor" href="https://discuss.afpy.org#p-11506-votre-mission-1" name="p-11506-votre-mission-1"></a>Votre mission</h4>
<ul>
<li>
<p>La majorité de votre travail sera dédiée à la solution « <a href="https://publik.entrouvert.com/publik-famille/" rel="noopener nofollow ugc">Publik Famille</a> », un outil pour aider les mairies à la gestion des écoles, cantines, centres de loisirs, crèches, etc.</p>
</li>
<li>
<p>Après un temps de formation avec l’équipe, vous travaillerez à l’amélioration et sur les évolutions de Publik Famille en suivant les tickets et en participant à élaborer la roadmap.</p>
</li>
<li>
<p>Vous relirez des patches proposés par les collègues, chercherez à les améliorer, bref, vous ferez du <em>code review</em>.</p>
</li>
<li>
<p>Vous participerez également au support technique pour les collectivités utilisant Publik Famille.</p>
</li>
</ul>
<h4><a class="anchor" href="https://discuss.afpy.org#p-11506-quelques-exemples-de-notre-quotidien-2" name="p-11506-quelques-exemples-de-notre-quotidien-2"></a>Quelques exemples de notre quotidien</h4>
<ul>
<li>
<p>du code sur <a href="https://git.entrouvert.org/" rel="noopener nofollow ugc">https://git.entrouvert.org/</a> avec par exemple <a href="https://git.entrouvert.org/entrouvert/combo" rel="noopener nofollow ugc">https://git.entrouvert.org/entrouvert/combo</a> (sorte de « CMS » pour faire des portails), <a href="https://git.entrouvert.org/entrouvert/wcs" rel="noopener nofollow ugc">https://git.entrouvert.org/entrouvert/wcs</a> (outil de construction de formulaires) ou <a href="https://git.entrouvert.org/entrouvert/lingo" rel="noopener nofollow ugc">https://git.entrouvert.org/entrouvert/lingo</a> (gestions des paiements et de la facturation)</p>
</li>
<li>
<p>un redmine pour gérer les tickets : <a href="https://dev.entrouvert.org/" rel="noopener nofollow ugc">https://dev.entrouvert.org/</a> avec par exemple <a href="https://dev.entrouvert.org/projects/combo" rel="noopener nofollow ugc">https://dev.entrouvert.org/projects/combo</a>, <a href="https://dev.entrouvert.org/projects/wcs" rel="noopener nofollow ugc">https://dev.entrouvert.org/projects/wcs</a> ou <a href="https://dev.entrouvert.org/projects/lingo" rel="noopener nofollow ugc">https://dev.entrouvert.org/projects/lingo</a></p>
</li>
<li>
<p>l’offre commerciale correspondante à toutes ces lignes de code s’appelle Publik : <a href="https://publik.entrouvert.com/" rel="noopener nofollow ugc">https://publik.entrouvert.com/</a></p>
</li>
<li>
<p>ce que ça donne : <a href="https://services.nancy.fr/" rel="noopener nofollow ugc">https://services.nancy.fr/</a>, <a href="https://mes-demarches.marseille.fr/" rel="noopener nofollow ugc">https://mes-demarches.marseille.fr/</a>, <a href="https://www.toodego.com/" rel="noopener nofollow ugc">https://www.toodego.com/</a>, <a href="https://services.cnil.fr/" rel="noopener nofollow ugc">https://services.cnil.fr/</a>, —  et de manière plus spécifique elles sont assemblées pour produire <a href="https://www.entrouvert.com/que-faisons-nous/solution-famille/" rel="noopener nofollow ugc">Publik Famille</a></p>
</li>
</ul>
<h4><a class="anchor" href="https://discuss.afpy.org#p-11506-les-conditions-de-travail-3" name="p-11506-les-conditions-de-travail-3"></a>Les conditions de travail</h4>
<ul>
<li>
<p>CDI de 52 000 € brut annuel, soit environ 3300 € net par mois — même salaire pour tout le monde.</p>
</li>
<li>
<p>99% des bénéfices répartis à parts égales entre les travailleuses·eurs, sous forme de participation, intéressement, primes (voir <a href="https://www.pappers.fr/entreprise/entrouvert-443170139" rel="noopener nofollow ugc">pappers.fr</a> pour vous donner une idée).</p>
</li>
<li>
<p>Organisation du temps de travail sur 4 jours de la semaine.</p>
</li>
<li>
<p>Travail à Paris XIVème ou à Lyon, télétravail possible depuis partout en France.</p>
</li>
<li>
<p>Horaires souples.</p>
</li>
<li>
<p>Mutuelle familiale.</p>
</li>
<li>
<p>8½ semaines de congés payés.</p>
</li>
<li>
<p>50% de la carte Navigo, café, thé et chocolat inclus dans les bureaux parisiens et lyonnais.</p>
</li>
<li>
<p>Un bon ThinkPad, accompagné d’un grand écran, avec un beau clavier et une souris optique qui brille dans le noir (sans oublier un budget annuel pour tout type de matériel utile pour le télétravail).</p>
</li>
<li>
<p>Coopératrice·teur, associé·e de la SCOP, à part égale de tous les autres.</p>
</li>
</ul>
<h4><a class="anchor" href="https://discuss.afpy.org#p-11506-cest-trop-beau-4" name="p-11506-cest-trop-beau-4"></a>C’est trop beau !</h4>
<p>Si vous avez lu notre annonce jusqu’ici et que vous vous dites, « c’est trop beau un job pareil, où est le piège ? », quelques éléments sur les difficultés à travailler dans une société comme  Entr’ouvert :</p>
<ul>
<li>
<p>Nous sommes tous partiellement patrons de notre entreprise, ce qui est souvent synonyme d’un engagement plus conséquent que si nous n’étions que salarié·es.</p>
</li>
<li>
<p>Ne pas avoir de patrons dans une entreprise à <em>n</em> coopérateurs·rices, cela veut dire avoir <em>n-1</em> « quasi-patrons » avec qui échanger : de bonnes capacités de communication, voire de diplomatie, sont nécessaires.</p>
</li>
<li>
<p>Pour les personnes en télétravail, la frontière est parfois ténue entre autonomie et isolement.</p>
</li>
</ul>
<p>Vous avez l’impression de ne pas correspondre entièrement au profil, cette annonce vous fait très envie mais vous doutez de vos capacités ? Écoutez votre cœur et postulez ! Les offres d’emploi décrivent toujours une personne qui n’existe pas : vous avez toutes vos chances.</p>
<h4><a class="anchor" href="https://discuss.afpy.org#p-11506-le-processus-de-recrutement-5" name="p-11506-le-processus-de-recrutement-5"></a>Le processus de recrutement</h4>
<p><strong>Les candidatures doivent être envoyées avant le dimanche 14 septembre 2025 à 23h59</strong>. Le déroulé est ensuite l’organisation d’un entretien de présentation mutuelle, suivi de l’envoi d’un court test technique puis un second entretien de débrief et discussion avec des membres de l’équipe technique. Les deux entretiens auront lieu par visio-conférence.</p>
<p><a href="https://formulaires-www.entrouvert.com/perennes/candidature-developpeureuse-python-django/" rel="noopener nofollow ugc">Le formulaire de candidature</a></p>
<p>Post-scriptum : merci aux cabinets de recrutement de <strong>ne pas</strong> nous contacter ; nous recherchons des coopératrices·eurs voulant s’impliquer dans notre structure et non des salarié·es proposés sur catalogue.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/entr-ouvert-developpeur-euse-python-django-paris-lyon-teletravail/2745">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>thomasnoel</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115140477034894338" />
        <id>https://mamot.fr/@AFPy/115140477034894338</id>
        <updated>2025-09-03T13:57:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Call for sponsors for PyConFR 2025<br />- support a free conference<br />- promotes your brand to the French Python community<br />- gain visibility
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115140466600655453" />
        <id>https://mamot.fr/@AFPy/115140466600655453</id>
        <updated>2025-09-03T13:54:52Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Appel à sponsors pour la PyConFR 2025 qui se déroule à Lyon. Avantages écrits :<br />- soutient une conférence gratuite<br />- met en avant votre marque auprès de la communauté francophone Python<br />- gain en visibilité
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Python: The Documentary | An origin story</title>
        <link href="https://discuss.afpy.org/t/python-the-documentary-an-origin-story/2743" />
        <id>https://discuss.afpy.org/t/python-the-documentary-an-origin-story/2743</id>
        <updated>2025-09-02T18:12:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://www.youtube.com/watch?v=GfH4QL4VqJ0">Python: The Documentary | An origin story</a></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/python-the-documentary-an-origin-story/2743">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>kirisakow</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris - Meetup le 16 octobre</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-le-16-octobre/2735" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-le-16-octobre/2735</id>
        <updated>2025-08-27T15:29:17Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ça fait longtemps alors un peu avant de se retrouver à la PyconFR, je vous propose ce meetup ou nous serons gentiment logés et nourris.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-16-octobre/2735/1">Sur Paris - Meetup le 16 octobre</a></p>
<p>2025-10-16 18:45 (Europe/Paris) → 2025-10-16 22:00 (Europe/Paris)</p>
</div>
<p>Lieu : Web-atrio 132 rue de Rivoli, 75001 · Paris</p>
<p>2-3 talks de 20-30min sont prévus ; si quelqu’un ici présent a envie de se proposer il reste des places <img alt=":wink:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/wink.png?v=14" title=":wink:" width="20"/> !</p>
<p>Je donnerai plus de détail quand on se rapprochera de la date.</p>
<p><small>5 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-16-octobre/2735">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Chadys</name>
        </author>
    </entry>
    <entry>
        <title>Incident du 26 août 2025 ayant touché les serveurs de production et de développement</title>
        <link href="https://linuxfr.org/news/incident-du-26-aout-2025-ayant-touche-les-serveurs-de-production-et-de-developpement" />
        <id>https://linuxfr.org/news/incident-du-26-aout-2025-ayant-touche-les-serveurs-de-production-et-de-developpement</id>
        <updated>2025-08-27T13:59:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Il y a exactement deux mois, un incident était survenu suite à un redémarrage brutal du serveur hébergeant les conteneurs de production et de développement ayant entraîné une attribution inattendue d’adresses IP. Et des réponses techniques <em>502 Bad Gateway</em> pour notre lectorat.</p>
<p>Ce 26 août, vers 15:22, un message peu engageant est arrivé par pneumatique sur nos téléscripteurs (via Signal pour être précis) : « <em>Tiens c’est bizarre j’ai perdu accès au site. Et au serveur <code>oups</code>.</em> » L’après-midi et la soirée furent longues.</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116110" hreflang="fr" title="https://linuxfr.org/news/incident-du-26-juin-2025-ayant-touche-les-serveurs-de-production-et-de-developpement">Incident du 26 juin 2025 ayant touché les serveurs de production et de développement</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-premier-diagnostic">Premier diagnostic</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-eh-bien-des-requ%C3%AAtes-habituelles">Eh bien des requêtes habituelles…</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-la-boucle-sans-fin">La boucle sans fin</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-une-derni%C3%A8re-page-depub">Une dernière page d’epub ?</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-retour-en-graphiques-sur-la-journ%C3%A9e">Retour en graphiques sur la journée</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-mesures-pr%C3%A9ventives-et-correctives">Mesures préventives et correctives</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-bonus-inattendu-pour-lincident-pr%C3%A9c%C3%A9dent-du-26-juin-2025">Bonus inattendu pour l’incident précédent du 26 juin 2025</a></li>
</ul>
</li>
</ul>
<h3 id="toc-premier-diagnostic">Premier diagnostic</h3>
<p>Le serveur répond au <em>ping</em> et permet les connexions TCP port 22, mais pas le SSH. Et les services web ne répondent plus. Souci matériel ? Noyau en vrac ? Attaque en cours ? Les spéculations vont bon train.</p>
<p>La connexion au serveur revient par intermittence, permettant à un moment d’exécuter quelques commandes, à d’autres d’attendre longuement pour l’affichage d’un caractère ou l’exécution de la commande tapée.</p>
<p>Le premier contact réétabli avec le serveur est assez clair (une forte charge) :</p>
<pre><code class="bash">$ uptime
<span class="m">15</span>:06:59 up <span class="m">2</span> days,  <span class="m">2</span>:54,  <span class="m">1</span> user,  load average: <span class="m">50</span>,00, <span class="m">205</span>,21, <span class="m">260</span>,83</code></pre>
<p>(dernier redémarrage le week-end précédent, mais surtout une charge système moyenne respectivement de 50, 205 et 261 sur les 1, 5 et 15 dernières minutes)</p>
<p>Initialement on suppose qu’il s’agit d’un trop grand nombre de requêtes ou de certaines requêtes tentant des injections de code sur le site (bref le trafic de fond plutôt habituel et permanent), et on ajoute des règles de filtrage péniblement et lentement pour bloquer les IP qui ressortent le plus dans nos logs.</p>
<p>Le site est alors inaccessible pendant plusieurs périodes. On arrête et relance ensuite plusieurs fois les services en pensant avoir ajouté suffisamment de filtrage, mais rapidement le serveur se retrouve englué. Les services sont alors arrêtés plus longuement le temps d’analyser les logs au calme. Au calme inclut notamment ne pas juste disposer d’une connexion <em>ssh</em> depuis un <em>smartphone</em>, mais plutôt d’un clavier et d’un grand écran par exemple, de l’accès à tous les secrets et toute la documentation aussi.</p>
<p>Finalement le trafic n’est pas énorme (en volume total) et si les requêtes hostiles sont bien présentes, rien ne semble inhabituel. Par contre les processus de coloration syntaxique partent en vrille, consommant chacun un processeur et aspirant allègrement la mémoire disponible. Avant d’être éliminés par le noyau Linux.</p>
<p>La console est remplie d’élimination de processus de ce type :</p>
<p><img alt="Le plein d’OutOfMemory" src="https://linuxfr.org/images/historique/serveurs/incident-du-26-aout-2025/le-plein-d-OOM.png"/></p>
<p>Mais si rien n’a changé niveau logiciel sur le conteneur LXC de production et si les requêtes ne sont pas inhabituelles, qu’est-ce qui peut bien écrouler le serveur et créer ces processus gourmands ?</p>
<h3 id="toc-eh-bien-des-requêtes-habituelles">Eh bien des requêtes habituelles…</h3>
<p>Pendant les phases d’attente lorsque le serveur ne répondait plus vraiment, nous avons noté qu'<a href="https://linuxfr.org/suivi/coloration-syntaxique-cassee">une nouvelle entrée de suivi a été créée</a> (merci BAud et merci RSS/Atom pour nous avoir permis de la voir alors que le serveur ne répondait déjà plus). Elle indique que la coloration syntaxique ne marche plus sur le site. Notamment l’exemple donné dans la documentation.</p>
<p>Pourtant le rendu fonctionne en testant en ligne de commande avec <code>pygmentize</code>.</p>
<p>Mais oui en testant l’exemple donné via le site, il est créé un processus Python2 <code>pygment</code> qui commence à se gaver de ressources.</p>
<p>Et en regardant les différents contenus et commentaires créés sur le site autour de l’incident, en filtrant sur ceux contenant des blocs avec de la coloration syntaxique, la <a href="https://linuxfr.org/news/g-mic-3-6-l-art-de-soigner-ses-images">dépêche (alors en préparation) sur G'MIC 3.6</a> apparaît. Et en testant cette dépêche, il est bien créé quatre processus Python2 <code>pygment</code> qui se gavent de ressources et ne semblent jamais vouloir se terminer. À rapprocher par exemple d’une page qui a été servie en 6785.9978s.</p>
<p><img alt="4 processus gourmands" src="https://linuxfr.org/images/historique/serveurs/incident-du-26-aout-2025/py-vener.png"/></p>
<p>OK, le souci vient de requêtes tout à fait habituelles de coloration syntaxique, reste à comprendre pourquoi ces processus tournent mal.</p>
<h3 id="toc-la-boucle-sans-fin">La boucle sans fin</h3>
<p>Un petit <code>strace</code> pour suivre les appels système en cours sur un des processus infernaux relève une boucle assez violente :</p>
<pre><code>(...)
close(623199355)                        = -1 EBADF (Bad file descriptor)
close(623199356)                        = -1 EBADF (Bad file descriptor)
close(623199357)                        = -1 EBADF (Bad file descriptor)
(...)
</code></pre>
<p>Il semble y avoir une immense itération sur des descripteurs de fichiers, en vue de les fermer, mais à l’aveugle, sans savoir s’ils existent réellement.</p>
<p>En regardant le code du composant utilisé (pygments), il semble n'y avoir qu'un seul appel à <code>close()</code> :</p>
<pre><code class="python"><span class="c1"># close fd's inherited from the ruby parent</span>
        <span class="kn">import</span> <span class="nn">resource</span>
        <span class="n">maxfd</span> <span class="o">=</span> <span class="n">resource</span><span class="o">.</span><span class="n">getrlimit</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">RLIMIT_NOFILE</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">maxfd</span> <span class="o">==</span> <span class="n">resource</span><span class="o">.</span><span class="n">RLIM_INFINITY</span><span class="p">:</span>
            <span class="n">maxfd</span> <span class="o">=</span> <span class="mi">65536</span>

        <span class="k">for</span> <span class="n">fd</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">maxfd</span><span class="p">):</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">os</span><span class="o">.</span><span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span>
            <span class="k">except</span><span class="p">:</span>
                <span class="k">pass</span></code></pre>
<p>Donc on itère sur tous les descripteurs entre 3 et le maximum déterminé…</p>
<pre><code class="python"><span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">resource</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">getrlimit</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">RLIMIT_NOFILE</span><span class="p">)[</span><span class="mi">1</span><span class="p">])</span>
<span class="mi">524288</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">RLIM_INFINITY</span><span class="p">)</span>
<span class="o">-</span><span class="mi">1</span></code></pre>
<p>Un demi-million de fois ici donc. L’objectif initial de la boucle est de fermer les descripteurs de fichiers provenant du processus Ruby père, issue du <em>fork</em> via <a href="https://www.rubydoc.info/stdlib/open3/Open3.popen3">Open3.popen3</a>. La version suivante du composant la remplace d’ailleurs par un ajout de l'<a href="https://docs.ruby-lang.org/en/master/Process.html#module-Process-label-File+Descriptor+Inheritance">option <em>:close_others</em></a>, qui précisément « <em>modifie l’héritage [des descripteurs de fichiers du processus parent] en fermant les non-standards (numéros 3 et plus grands)</em> ».</p>
<p>Sur une Debian 12, la limite du nombre de fichiers par défaut, c’est 1 048 576. C’est déjà probablement bien plus que la valeur qui prévalait à l’époque où a été écrit la boucle Python (on avait des limitations à 4096 à une époque reculée). Mais il s’avère que durant le week-end l’hôte du conteneur de production a été migré en Debian 13. Sans modification du conteneur de production pensions-nous. Sans modification <em>directe</em> du conteneur de production. Mais quid d’une modification <em>indirecte</em> ? Par exemple si la limite par défaut des « Max open files » était passée à 1 073 741 816 sur l’hôte, soit 1024 fois plus que quelques jours auparavant. Et donc des boucles nettement plus longues voire sans fin, sans libération de mémoire.</p>
<p>On ne peut mettre à jour le composant <em>pygments</em> dans l’immédiat, mais on peut limiter les dégâts en abaissant la limite du nombre de descripteurs de fichiers à quelque chose de raisonnable (i.e. on va gaspiller raisonnablement des cycles CPU dans une boucle un peu inutile mais brève…). Une édition de <code>/etc/security/limits.conf</code>, un redémarrage du conteneur de production et on peut vérifier que cela va nettement mieux avec cette réparation de fortune.</p>
<h3 id="toc-une-dernière-page-depub">Une dernière page d’epub ?</h3>
<p>Le conteneur LXC portant le service <em>epub</em> de production a assez mal pris la surcharge du serveur, et vers 20h08, <code>systemd-networkd</code> sifflera la fin de la récré avec un  <em>eth0: The interface entered the failed state frequently, refusing to reconfigure it automatically</em> (quelque chose comme « ça n’arrête pas d’échouer, débrouillez-vous sans moi »). Le service <em>epub</em> est resté en carafe jusqu’au 27 août vers 13h31 (<a href="https://linuxfr.org/suivi/le-telechargement-en-epub-n-aboutit-pas">merci pour l’entrée de suivi</a>).</p>
<p>Voir ce <a href="https://linuxfr.org/news/incident-du-26-juin-2025-ayant-touche-les-serveurs-de-production-et-de-developpement#comment-1998422">commentaire sur la dépêche de l’incident précédent</a> expliquant la séparation du service <em>epub</em> et du conteneur principal de production (en bref : dette technique et migration en cours).</p>
<h3 id="toc-retour-en-graphiques-sur-la-journée">Retour en graphiques sur la journée</h3>
<p>Le serveur était très occupé. Au point de n’avoir pas le temps de mettre à jour les graphiques de temps en temps.</p>
<p>Rétrospectivement les processeurs du serveur ont travaillé dur : 140 de charge sur le graphique (mais avec des pics jusque 260 d’après la commande <code>uptime</code>), contre moins de 5 en temps normal (un <em>petit</em> facteur de 28 à 52   ô_Ô)</p>
<p><img alt="Charge CPU" src="https://linuxfr.org/images/historique/serveurs/incident-du-26-aout-2025/charge-CPU.png"/></p>
<p>Et l’utilisation de la  mémoire montre aussi de brutaux changements de comportement : libération intempestive de mémoire (<em>Free</em>, en vert), utilisation mémoire plus importante que d’habitude (<em>Used</em>, en jaune), là où le comportement normal est d’avoir le maximum en cache (<em>Cached</em>, en orange) et des processus tellement peu consommateurs en RAM que cela n’apparaît normalement pas.</p>
<p><img alt="Utilisation mémoire" src="https://linuxfr.org/images/historique/serveurs/incident-du-26-aout-2025/memoire.png"/></p>
<h3 id="toc-mesures-préventives-et-correctives">Mesures préventives et correctives</h3>
<p>Dans les actions en cours ou à prévoir :</p>
<ul>
<li>mettre à jour la documentation pour disposer facilement et rapidement des informations pour les connexions aux cartes d’administration ou les procédures de blocages d’IP</li>
<li>procéder à la montée de version des composants (<em>yapuka</em>, épineux sujet de la dette technique à éponger)</li>
<li>vérifier l’efficacité des limitations CPU/mémoire mises sur certains conteneurs LXC et les étendre aux autres</li>
<li>mettre des limites sur des processus particuliers (comme ceux de <em>pygments</em>)</li>
<li>ajouter le déploiement des limites par utilisateur dans le code Ansible</li>
<li>corriger la collecte <code>rrd</code> des métriques concernant les interfaces réseau</li>
<li>remonter les alertes OOM qui ne sont pas <em>normales</em>
</li>
<li>comprendre la surconsommation mémoire ? (les boucles actives expliquent la consommation processeur, mais pour la mémoire ?)</li>
</ul>
<h3 id="toc-bonus-inattendu-pour-lincident-précédent-du-26-juin-2025">Bonus inattendu pour l’incident précédent du 26 juin 2025</h3>
<p>De façon cocasse, ce nouvel incident et le temps passé à parcourir les différents logs ont permis de <a href="https://linuxfr.org/nodes/139566/comments/1998592">retrouver les infos de la carte d’administration distante</a> et d’expliciter l’origine du redémarrage serveur intempestif. À quelque chose malheur est bon, si on peut dire. Ceci n’est pas une invitation pour un prochain incident.</p>
</div><div><a href="https://linuxfr.org/news/incident-du-26-aout-2025-ayant-touche-les-serveurs-de-production-et-de-developpement.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/140084/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/incident-du-26-aout-2025-ayant-touche-les-serveurs-de-production-et-de-developpement#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Benoît Sibaud,BAud,Xavier Teyssier,Jona</name>
        </author>
    </entry>
    <entry>
        <title>Microdot : Un framework web ultra-léger pour Python et MicroPython</title>
        <link href="https://github.com/miguelgrinberg/microdot" />
        <id>https://github.com/miguelgrinberg/microdot</id>
        <updated>2025-08-25T13:15:54Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez Microdot, un framework web minimaliste conçu pour Python et MicroPython. Développé par Miguel Grinberg, ce projet open source se distingue par son extrême légèreté, le rendant particulièrement adapté pour les projets IoT et les environnements avec des ressources limitées. Une alternative intéressante pour les développeur·se·s Python cherchant une solution web simple et efficace.</p>
<a href="https://news.humancoders.com/t/python/items/38306-microdot-un-framework-web-ultra-leger-pour-python"><img src="https://opengraph.githubassets.com/f443f1e5154d5b66cffcbdb4e9ca58fbd826f34bc14d6811883b9313617d1e90/miguelgrinberg/microdot"/></a><hr/><a href="https://news.humancoders.com/t/python/items/38306-microdot-un-framework-web-ultra-leger-pour-python#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/38306-microdot-un-framework-web-ultra-leger-pour-python">Microdot : Un framework web ultra-léger pour Python et MicroPython</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 27 août</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-27-aout/2729" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-27-aout/2729</id>
        <updated>2025-08-18T10:27:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Pour ce deuxième meetup de l’été, on se retrouve à partir de 18h à <a href="https://www.reperes-lyon.fr/">Repère(s)</a> (Croix-Paquet).</p>
<p>L’été, il n’y a pas de présentation, juste un grand moment d’échange <img alt=":sun:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/sun.png?v=14" title=":sun:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-27-aout/2729/1">C’est l’été</a></p>
<p>2025-08-27 18:00 (Europe/Paris) → 2025-08-27 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-27-aout/2729">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115027348066779849" />
        <id>https://mamot.fr/@AFPy/115027348066779849</id>
        <updated>2025-08-14T14:27:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Registration is now open (mandatory and free) for PyConFR 2025, taking place from October 30 to November 2, 2025.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/115027341138814918" />
        <id>https://mamot.fr/@AFPy/115027341138814918</id>
        <updated>2025-08-14T14:25:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Inscription ouverte (obligatoire et gratuite) pour la PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Quam Facere : Nouvelle version</title>
        <link href="https://linuxfr.org/users/seraf1/journaux/quam-facere-nouvelle-version" />
        <id>https://linuxfr.org/users/seraf1/journaux/quam-facere-nouvelle-version</id>
        <updated>2025-08-13T13:43:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 id="toc-quam-facere-quest-ce-donc">Quam Facere, qu'est-ce donc ?</h2>
<p>C'est une appli web développée en Python/Flask/SQLAlchemy pour la gestion des procédures informatiques avec la possibilité de lancer des opérations basées sur ces procédures.</p>
<h3 id="toc-fonctionnalités-clés-">Fonctionnalités clés :</h3>
<ul>
<li>Création et exécution de procédures avec variables dynamiques</li>
<li>Gestion d'équipes hiérarchiques avec permissions</li>
<li>Suivi en temps réel des opérations</li>
<li>Export de documentation (Markdown, PDF, DOCX, etc.)</li>
<li>Interface multilingue (Français/Anglais)</li>
</ul>
<h2 id="toc-quelles-nouvelles">Quelles nouvelles ?</h2>
<ul>
<li>Bascule de Bulma vers Bootstrap pour l'interface</li>
<li>Validation du compte par mail</li>
<li>Correction de nombreux petits Bug</li>
</ul>
<h2 id="toc-retour">Retour</h2>
<p>JE suis bien évidemment preneur de tout retour que vous pourriez me faire, soit en commentaire de ce journal, soit en ouvrant un ticket sur Codeberg.</p>
<h2 id="toc-les-liens">Les liens</h2>
<ul>
<li>Sources : <a href="https://codeberg.org/spn109/Quam_Facere">https://codeberg.org/spn109/Quam_Facere</a>
</li>
<li>Site : <a href="https://spn109.fr/qf">https://spn109.fr/qf</a>
</li>
<li>Demo : <a href="https://qf-demo.spn109.fr">https://qf-demo.spn109.fr</a>
</li>
</ul>
<div><a href="https://linuxfr.org/users/seraf1/journaux/quam-facere-nouvelle-version.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139987/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/seraf1/journaux/quam-facere-nouvelle-version#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>seraf1</name>
        </author>
    </entry>
    <entry>
        <title>Chef-Cheffe de projets web appli­ca­tifs confirmé-e  / Toulouse / CDD 12 mois</title>
        <link href="https://discuss.afpy.org/t/chef-cheffe-de-projets-web-appli-ca-tifs-confirme-e-toulouse-cdd-12-mois/2724" />
        <id>https://discuss.afpy.org/t/chef-cheffe-de-projets-web-appli-ca-tifs-confirme-e-toulouse-cdd-12-mois/2724</id>
        <updated>2025-08-12T07:53:13Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://makina-corpus.com/" rel="noopener nofollow ugc"><strong>Makina Corpus</strong></a> <strong>développe des projets web ou mobiles d’envergure</strong> combinant notamment la cartographie, l’intelligence artificielle, le traitement et l’analyse de données, la dataviz. Nos applications phares sont au service de domaines tels que la randonnée et la gestion d’espaces naturels (Geotrek), l’aménagement et le développement économique de territoires (Actif), <a href="https://makina-corpus.com/application-web-mobile/regard-altitude-outil-open-source-comprendre-agir-changement-climatique#corps" rel="noopener nofollow ugc">la prévention des risques naturels</a>, <a href="https://makina-corpus.com/gestion-de-leau/refonte-accueil-hydroportail-schapi#corps" rel="noopener nofollow ugc">la gestion de l’eau</a>…</p>
<p><strong>Notre organisation et nos prestations se construisent sur trois piliers</strong> : les logiciels libres, le respect de l’humain et l’engagement en faveur de l’environnement; trois valeurs fondamentales que nous développons et renforçons grâce à notre charte RSE.</p>
<p><em>Découvrez quelques uns de nos projets : <a class="inline-onebox" href="https://makina-corpus.com/references" rel="noopener nofollow ugc">Références | Makina Corpus</a>, et retrouvez-nous sur Welcome To The Jungle (<a class="inline-onebox" href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Makina Corpus : photos, vidéos, recrutement</a>).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-11371-la-mission-1" name="p-11371-la-mission-1"></a>La mission</h2>
<p>Dans le cadre du rempla­ce­ment d’un chef de projet vous inté­gre­rez l’ac­ti­vité « éditeur logi­ciel » de Makina Corpus et aurez pour mission de pilo­ter <strong>une suite appli­ca­tive open-source dédiée au suivi de la biodi­ver­sité pour les collec­ti­vi­tés.</strong></p>
<p><strong>Vos missions consis­te­ront à :</strong></p>
<ul>
<li>Iden­ti­fier et mettre en œuvre au sein des projets les <strong>besoins tech­nico-fonc­tion­nels</strong> des clients ;</li>
<li>Forma­li­ser, orga­ni­ser, plani­fier et contrô­ler les phases de réali­sa­tion ;</li>
<li><strong>Pilo­ter et coor­don­ner</strong> l’équipe projet ;</li>
<li>Assu­rer le suivi du plan­ning et le contrôle de la qualité ;</li>
<li>Gérer les <strong>enga­ge­ments vis-à-vis du client</strong> et s’as­su­rer de sa satis­fac­tion ;</li>
<li><strong>Fidé­li­ser</strong>, entre­te­nir et déve­lop­per le porte­feuille client exis­tant ;</li>
<li>Parti­ci­per aux phases d’avant-vente en rela­tion avec le client et avec nos équipes, rédi­ger une propo­si­tion commer­ciale.</li>
</ul>
<p><strong>Vous devrez acqué­rir une connais­sance fonc­tion­nelle pous­sée sur l’ou­til</strong> pour conseiller et accom­pa­gner les clients, et travailler avec l’équipe tech­nique.</p>
<p>Nous mettrons en place un accom­pa­gne­ment adapté et de courte durée pour vous permettre d’ac­qué­rir rapi­de­ment une très bonne connais­sance de l’en­tre­prise, son acti­vité et son envi­ron­ne­ment.</p>
<p><em>Ce poste est basé à Toulouse et ouvert au télé­tra­vail partiel (jusqu’à 3 jours/semaine car il néces­site de venir en présen­tiel à l’agence au mini­mum 2j/semaine).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-11371-profil-2" name="p-11371-profil-2"></a>Profil</h2>
<p><strong>Vous maîtri­sez les méthodes et outils de gestion de projets web complexes et tech­niques, et possé­dez une expé­rience récente de 5 ans mini­mum sur ce type de poste et ce péri­mètre de missions.</strong> Vous avez une appé­tence commer­ciale et idéa­le­ment une expé­rience dans la réponse à appels d’offres.</p>
<ul>
<li>Vous aimez comprendre les besoins du client, s’ap­pro­prier son métier et lui propo­ser des solu­tions adap­tées ;</li>
<li>Vous êtes très à l’aise avec l’en­vi­ron­ne­ment du web et avec les aspects fonc­tion­nels des appli­ca­tions web ;</li>
<li>Votre goût du travail en équipe, votre curio­sité, vos excel­lentes quali­tés rela­tion­nelles seront des atouts indis­pen­sables. Apprendre toujours plus vous stimule !</li>
</ul>
<p><em>Nous ne préci­sons pas de diplôme ou de niveau d’études mini­mum</em> <em>car nous atta­chons avant tout de l’im­por­tance aux compé­tences et à la passion du métier.</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-11371-informations-complmentaires-3" name="p-11371-informations-complmentaires-3"></a>Infor­ma­tions complé­men­taires</h2>
<p>Dans la ruche colla­bo­ra­tive Makina Corpus, <strong>on dit ce qu’on fait</strong> : les maki­niens évoluent dans une ambiance moti­vante et stimu­lante (projets et contrib open­source, parti­ci­pa­tions encou­ra­gées à des évène­ments/meetup, émula­tion entre experts passion­nés, tech­nos inno­vantes à tester, veille…) et contri­buent aux valeurs humaines ancrées dans l’ADN de l’en­tre­prise (envi­ron­ne­ment, équi­libre vie pro/vie privée, colla­bo­ra­tif, télé­tra­vail…).</p>
<p>Mais surtout chez Makina <strong>on fait ce qu’on dit</strong> : vous avez besoin de le voir pour le croire ? Venez nous rencon­trer, un.e maki­nien.ne pourra vous en parler ! Nos équipes sont mixtes, femmes et hommes du numé­rique nous vous atten­dons.</p>
<p><strong>Écri­vez-nous et racon­tez qui vous êtes et ce qui vous anime</strong>. Expliquez-nous en quoi vos moti­va­tions et vos compé­tences sont en adéqua­tion avec nos valeurs et nos acti­vi­tés.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/chef-cheffe-de-projets-web-appli-ca-tifs-confirme-e-toulouse-cdd-12-mois/2724">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>La mécanique des imports en Python</title>
        <link href="https://zestedesavoir.com/articles/4762/la-mecanique-des-imports-en-python/" />
        <id>https://zestedesavoir.com/articles/4762/la-mecanique-des-imports-en-python/</id>
        <updated>2025-08-11T07:12:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Comprendre son comportement et le personnaliser
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>ConFoo Montreal 2026: L&#39;appel aux conférenciers est ouvert</title>
        <link href="https://linuxfr.org/news/confoo-montreal-2026-l-appel-aux-conferenciers-est-ouvert" />
        <id>https://linuxfr.org/news/confoo-montreal-2026-l-appel-aux-conferenciers-est-ouvert</id>
        <updated>2025-08-10T11:24:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>La conférence ConFoo est de retour pour sa 24 e édition, du 25 au 27 février 2026 à l’Hôtel Bonaventure de Montréal! Que vous soyez un développeur junior ou un CTO, venez découvrir pourquoi ConFoo est devenu l’un des événements phares pour les professionnels en hautes technologies.</p>
<p>Nous sommes présentement à la recherche d’experts d’expérience souhaitant joindre notre équipe de conférenciers pour l’édition 2026! De PHP à JavaScript, en passant par tous les enjeux liés à la sécurité et au développement de l’IA, ConFoo couvre chaque année l’ensemble des sujets qui font bouger l’industrie.</p>
<p>Offertes en français ou en anglais, nos présentations sont généralement d’un format de 45 minutes, incluant un 10 minutes de questions des participants. Nos conférenciers invités profitent aussi d’un traitement privilégié; comprenant la couverture de leurs frais de déplacement et d’hébergement, en plus de l’accès à l’expérience complète de l’événement (présentations, repas, etc.).</p>
<p>Vous avez jusqu’au 21 septembre prochain pour <a href="https://confoo.ca/fr/2026/call-for-papers">soumettre votre projet de présentation</a>!</p>
<p>Vous cherchez simplement à vous inscrire? Profitez dès maintenant d’un <a href="https://confoo.ca/fr/2026">rabais de 300$</a> en réservant votre place d’ici le 17 octobre!</p>
<p>Faites partie de l’aventure avec nous et découvrez comment l’intelligence humaine est en train de façonner le milieu des hautes technologies!</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/116055" hreflang="fr" title="https://confoo.ca/fr/2026/call-for-papers">Appel au conférenciers</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/116056" hreflang="fr" title="https://confoo.ca/fr/2026">ConFoo Montréal 2026</a></li></ul><div></div><div><a href="https://linuxfr.org/news/confoo-montreal-2026-l-appel-aux-conferenciers-est-ouvert.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139946/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/confoo-montreal-2026-l-appel-aux-conferenciers-est-ouvert#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Yann Larrivee,Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>Problème pour réinitialiser mon mot de passe sur le CFP de PyConFR</title>
        <link href="https://discuss.afpy.org/t/probleme-pour-reinitialiser-mon-mot-de-passe-sur-le-cfp-de-pyconfr/2722" />
        <id>https://discuss.afpy.org/t/probleme-pour-reinitialiser-mon-mot-de-passe-sur-le-cfp-de-pyconfr/2722</id>
        <updated>2025-08-10T11:06:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>J’ai récemment essayé de me reconnecter au CFP de PyConFR pour vérifier l’état de ma proposition. Lorsque j’ai voulu utiliser le bouton « réinitialiser le mot de passe », je n’ai reçu aucun e-mail.</p>
<p>Il est possible que j’aie soumis ma proposition avec une adresse e-mail erronée, car je ne reçois pas de message de réinitialisation, ni sur mon adresse personnelle, ni sur mon adresse professionnelle.</p>
<p>Pourriez-vous m’aider à résoudre ce problème ?</p>
<p>Merci d’avance pour votre aide.</p>
<p><small>8 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-pour-reinitialiser-mon-mot-de-passe-sur-le-cfp-de-pyconfr/2722">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>arruda</name>
        </author>
    </entry>
    <entry>
        <title>Comment Python est devenu une communauté, pas seulement un langage</title>
        <link href="https://thenewstack.io/how-python-grew-from-a-language-to-a-community/" />
        <id>https://thenewstack.io/how-python-grew-from-a-language-to-a-community/</id>
        <updated>2025-08-08T18:56:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article explique comment Python, au-delà de ses qualités techniques, s’est construit autour d’une communauté mondiale active et solidaire. Il met en lumière l’importance des contributions open source, des événements comme les conférences Python, et des initiatives éducatives qui ont façonné l’écosystème Python actuel. De simple langage de programmation, Python est devenu une culture, un réseau d’échange et de soutien, permettant à chacun de contribuer, d’apprendre, et de collaborer à l’échelle mondiale.</p>
<a href="https://news.humancoders.com/t/python/items/38045-comment-python-est-devenu-une-communaute-pas-seule"><img src="https://cdn.thenewstack.io/media/2025/08/686c6b18-paul-everitt-big-smile-interviewed-by-david-cassel-on-zoom-for-the-new-stack-july-25-2025-1024x586-1.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/38045-comment-python-est-devenu-une-communaute-pas-seule#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/38045-comment-python-est-devenu-une-communaute-pas-seule">Comment Python est devenu une communauté, pas seulement un langage</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Piloter firefox, mais pas que, avec DBUS</title>
        <link href="https://linuxfr.org/users/purplepsycho/journaux/piloter-firefox-mais-pas-que-avec-dbus" />
        <id>https://linuxfr.org/users/purplepsycho/journaux/piloter-firefox-mais-pas-que-avec-dbus</id>
        <updated>2025-08-07T09:06:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-intro-beaucoup-trop-longue">Intro beaucoup trop longue</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-quoi">Quoi</a></li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-comment">Comment</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-cest-bon-on-a-tout-pour-commencer">C'est bon on a tout pour commencer ??</a></li>
</ul>
</li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-impl%C3%A9mentations">Implémentations</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-python">python</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-c">C</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-shell">Shell</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-comparaison">Comparaison</a></li>
</ul>
</li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-la-suite">La suite</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-repo-git">Repo git</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="toc-intro-beaucoup-trop-longue">Intro beaucoup trop longue</h3>
<p>Sur ma liste de choses à faire[1], j'avais marqué "apprendre dbus" il y a bien longtemps.</p>
<p>Sur mon PC, j'écoute de la musique via deezer, et parfois, c'est long quand je veux passer un morceau ou retourner sur le dernier --car j'aime écouter certains trucs en boucle, toi même tu sais-- : </p>
<ul>
<li>il faut retrouver firefox,</li>
<li>il faut retrouver le bon onglet,</li>
<li>il faut cliquer au bon endroit dans la page.</li>
</ul>
<p>Bref une perte de temps.</p>
<p>J'ai donc commencer à me demander comment piloter firefox autrement. L'idée, c'est de faire un programme qui va bien et de le lancer via une combinaison de touches (ou dans un bash, ou même un vim).</p>
<p><a href="https://github.com/snipem/deezer-cli">deezer-cli</a> permet de piloter Safari sur un Mac. L'idée est bonne : exécuter une commande js dans l'ongle deezer.<br/><br/>
Bon, c'est pas ce que je cherche, mais l'idée me plaît.</p>
<p>Et pourquoi pas lancer un serveur udp depuis un script greasemonkey pour faire la même chose ?</p>
<p>Je me voyais déjà ajouter <em>la</em> fonctionnalité manquante à firefox, devenir un nouveau gourou du logiciel libre, à moi la gloire, le succès et tout le reste.</p>
<p>Et pis, j'ai repensé à mon vieux casque bluetooth qui est capable de faire ça, <code>"&gt;*/×@)!</code> Quelqu'un avait déjà eu l'idée. Il y avait même un touche sur mon clavier pour mettre le flux audio en pause…</p>
<p>Après quelque recherche[2], j'ai trouvé ce que je cherchais : <strong>Piloter une interface mediaplayer2 via dbus</strong></p>
<h3 id="toc-quoi">Quoi</h3>
<p>Vas plutôt lire wikipedia, mais en gros, DBUS est un bus qui permet aux applications de proposer leurs services à qui en veut.</p>
<p>Par exemple, on peut allumer ou éteindre le bluetooth, éteindre l'ordinateur, envoyer une notification…</p>
<p>Et donc, on peut piloter un lecteur multimédia, via l'<a href="https://specifications.freedesktop.org/mpris-spec/latest/">interface MPRIS</a>[3].</p>
<h3 id="toc-comment">Comment</h3>
<p>Un peu de lecture plus tard, je trouve ce qui m'intéresse : l'interface <code>MediaPlayer2.Player</code> qui implémente --entre autres-- les méthodes </p>
<ul>
<li>
<code>Next</code>,</li>
<li>
<code>Previous</code>,</li>
<li>
<code>PlayPause</code>.</li>
</ul>
<p>Donc, c'est bon, j'ai ce qu'il faut maintenant ? Non, il manque l'objet à manipuler. Et cet objet n'a pas forcement un nom unique, il faudra donc le chercher…</p>
<p>Chaque objet dbus a un nom qu'il demande sur le bus, si un lecteur multimédia veut implémenter l'interface qui va bien <em>doit</em> avoir un nom qui commence par <code>org.mpris.MediaPlayer2</code>.</p>
<p>Il faut donc chercher les noms sur le bus qui commence par le motif indiqué.</p>
<p>Pour cela, on utilise l'interface <code>org.freedesktop.DBus</code> implémentée par l'objet <code>org.freedesktop.DBus</code> sur laquelle on doit appeler <code>ListNames</code>.</p>
<h4 id="toc-cest-bon-on-a-tout-pour-commencer">C'est bon on a tout pour commencer ??</h4>
<p>Non, et le chemin alors ?</p>
<p>Le chemin (<em>path</em> dans la langue des <em>Spices Girls</em>) correspond plus au moins à la notion de classe. En simple, c'est comme l'interface, mais dont on replace <code>.</code> par des <code>/</code>, et que l'on fait commencer par <code>/</code>.</p>
<p>Donc, l'interface "org.freedesktop.DBus" sera associé au chemin "/org/freedesktop/DBus".</p>
<p>Là, on a tout.</p>
<p>On va donc commencer par chercher la liste des objets dont le nom suit un certain motif.<br/><br/>
Si cet objet est unique, on peut appeler les fonctions qui nous intéressent, comme "Next" et les autres cités plus haut.</p>
<h3 id="toc-implémentations">Implémentations</h3>
<p>Il y a plein de <em>binding</em> de dbus. J'ai commencé avec un test en python, pour voir si ça marchait, puis en C par ce qu'on se refait pas et en bash, parce que je savais pas si c'était possible.</p>
<h4 id="toc-python">python</h4>
<p>J'aime pas python --pas le langage en lui même, mais la gestion des versions et des dépendances-- mais il faut bien lui reconnaître qu'il est facile d'accès et que sa bibliothèque dbus est bien documentée.</p>
<p>C'est facile et rapide, tellement que je peux mettre ici (réduit au minimum, c'est :</p>
<pre><code class="python"><span class="ch">#! /usr/bin/env python3</span>

<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">dbus</span> <span class="kn">import</span> <span class="n">SessionBus</span><span class="p">,</span> <span class="n">Interface</span>

<span class="c1"># On récupère le bus de session</span>
<span class="n">bus</span> <span class="o">=</span> <span class="n">SessionBus</span><span class="p">()</span>

<span class="c1"># On récupère l'objet qui nom permet d'énumérer les objets sur le bus de session</span>
<span class="n">session</span> <span class="o">=</span> <span class="n">bus</span><span class="o">.</span><span class="n">get_object</span><span class="p">(</span> <span class="s2">"org.freedesktop.DBus"</span><span class="p">,</span> <span class="s2">"/org/freedesktop/DBus"</span><span class="p">)</span>

<span class="c1"># Et on appelle ListNames sur cet objet</span>
<span class="n">names</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">ListNames</span><span class="p">()</span>

<span class="c1"># Dont on récupère les objets dont le nom commence par ...</span>
<span class="n">players</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">names</span> <span class="k">if</span> <span class="mi">0</span> <span class="o">==</span> <span class="n">x</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">'org.mpris.MediaPlayer2'</span><span class="p">)]</span>

<span class="c1"># On veut un seul objet</span>
<span class="k">if</span> <span class="mi">1</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">players</span><span class="p">):</span>
    <span class="k">if</span> <span class="mi">0</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">players</span><span class="p">)</span> <span class="p">:</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'No player found</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'More than one player found</span><span class="se">\n</span><span class="s1">'</span><span class="p">)</span>
    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>

<span class="c1"># On récupère l'objet associé au nom</span>
<span class="n">player</span> <span class="o">=</span> <span class="n">bus</span><span class="o">.</span><span class="n">get_object</span><span class="p">(</span><span class="n">players</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="s1">'/org/mpris/MediaPlayer2'</span><span class="p">)</span>

<span class="c1"># Ainsi que l'interface</span>
<span class="n">interface</span> <span class="o">=</span> <span class="n">Interface</span><span class="p">(</span><span class="n">player</span><span class="p">,</span> <span class="n">dbus_interface</span><span class="o">=</span><span class="s1">'org.mpris.MediaPlayer2.Player'</span><span class="p">)</span>

<span class="c1"># Et on appelle la méthode qui va bien.</span>
<span class="n">interface</span><span class="o">.</span><span class="n">PlayPause</span><span class="p">()</span></code></pre>
<h4 id="toc-c">C</h4>
<p>En C, j'ai voulu utiliser la bibliothèque officielle (<a href="https://www.freedesktop.org/wiki/Software/DBusBindings/">libdbus</a>), mais j'ai lu :</p>
<blockquote>
<p>If you use this low-level API directly, you're signing up for some pain. —official API documentation</p>
</blockquote>
<p>Donc, je suis parti sur glib, parce que c'est rigolo de cherche de la doc sur la manipulation des GString sur internet.</p>
<p>C'est du même tonneau, mais avec des appels moins simples :</p>
<p>On récupère le bus avec la fonction qui va bien :</p>
<pre><code class="c">    <span class="n">GDBusConnection</span> <span class="o">*</span><span class="n">con</span> <span class="o">=</span> <span class="n">g_bus_get_sync</span><span class="p">(</span><span class="n">G_BUS_TYPE_SESSION</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span></code></pre>
<p>Et on appelle les méthode avec un gros pâté :</p>
<pre><code class="c"><span class="n">GVariant</span> <span class="o">*</span><span class="n">result</span> <span class="o">=</span> <span class="n">g_dbus_connection_call_sync</span><span class="p">(</span>
    <span class="n">con</span><span class="p">,</span>                        <span class="c1">// connexion au bus</span>
    <span class="s">"org.freedesktop.DBus"</span><span class="p">,</span>     <span class="c1">// nom</span>
    <span class="s">"/org/freedesktop/DBUS"</span><span class="p">,</span>    <span class="c1">// chemin</span>
    <span class="s">"org.freedesktop.DBus"</span><span class="p">,</span>     <span class="c1">// interface</span>
    <span class="s">"ListNames"</span><span class="p">,</span>                <span class="c1">// methode </span>
    <span class="nb">NULL</span><span class="p">,</span>                       <span class="c1">// parametre</span>
    <span class="n">G_VARIANT_TYPE</span><span class="p">(</span><span class="s">"(as)"</span><span class="p">),</span>     <span class="c1">// sortie attendue: tableau de chaines</span>
    <span class="n">G_DBUS_CALL_FLAGS_NONE</span><span class="p">,</span>     <span class="c1">// pas de drapeau</span>
    <span class="mi">3000</span><span class="p">,</span>                       <span class="c1">// timeout</span>
    <span class="nb">NULL</span><span class="p">,</span>                       <span class="c1">// cancellable</span>
    <span class="nb">NULL</span><span class="p">);</span>                      <span class="c1">// error</span></code></pre>
<p>La partie pénible est de parcourir les résultats pour trouver l'objet qu'on veut car on doit faire attention à libérer explicitement la mémoire. Un fois l'objet voulu trouvé, on peut appeler la méthode voulue :</p>
<pre><code class="c"><span class="n">GVariant</span> <span class="o">*</span><span class="n">result</span> <span class="o">=</span> <span class="n">g_dbus_connection_call_sync</span><span class="p">(</span>
    <span class="n">con</span><span class="p">,</span>       
    <span class="n">player_name</span><span class="p">,</span>
    <span class="s">"/org/mpris/MediaPlayer2"</span><span class="p">,</span>    
    <span class="s">"org.mpris.MediaPlayer2.Player"</span><span class="p">,</span>    
    <span class="s">"PlayPause"</span><span class="p">,</span>              
    <span class="nb">NULL</span><span class="p">,</span>                    
    <span class="nb">NULL</span><span class="p">,</span>                    
    <span class="n">G_DBUS_CALL_FLAGS_NONE</span><span class="p">,</span> 
    <span class="mi">3000</span><span class="p">,</span>                  
    <span class="nb">NULL</span><span class="p">,</span>                 
    <span class="nb">NULL</span><span class="p">);</span></code></pre>
<p>Le code était un peu plus touffu, il est lisible <a href="https://framagit.org/mabu/dbus-media-control/-/tree/main/c">ici</a></p>
<h4 id="toc-shell">Shell</h4>
<p>Et pour bash, il existe <code>dbus-send</code> qui fait en gros ce que je veux en un seul appel (que j'aurais pu appeler en python ou en C si j'étais pervers)</p>
<pre><code class="bash"><span class="ch">#! /usr/bin/env bash</span>

<span class="c1"># à la recherche du player</span>
<span class="nv">PLAYER</span><span class="o">=</span><span class="k">$(</span>dbus-send --print-reply --session --dest<span class="o">=</span>org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames <span class="p">|</span> grep org.mpris.MediaPlayer2 <span class="p">|</span> sed s<span class="s1">'/.*"\([^"]*\)".*/\1/'</span><span class="k">)</span>

<span class="c1"># Meh, what if PLAYER is empty? wc -l will return 1</span>
<span class="c1"># should also test for PLAYER emptyness</span>
<span class="nv">COUNT</span><span class="o">=</span><span class="s2">"</span><span class="k">$(</span>wc -w <span class="o">&lt;&lt;&lt;</span> <span class="s2">"</span><span class="nv">$PLAYER</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>

<span class="k">if</span> <span class="o">[</span> <span class="m">0</span> -eq <span class="s2">"</span><span class="nv">$COUNT</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then</span>
    <span class="nb">echo</span> <span class="s2">"no player found"</span>
    <span class="nb">exit</span>
<span class="k">elif</span> <span class="o">[</span> <span class="m">1</span> -ne <span class="s2">"</span><span class="nv">$COUNT</span><span class="s2">"</span> <span class="o">]</span> <span class="p">;</span> <span class="k">then</span>
    <span class="nb">echo</span>  <span class="s2">"More than one player found"</span>
    <span class="nb">exit</span>
<span class="k">fi</span>

<span class="c1"># appel de la méthode voulue</span>
<span class="m">1</span>&gt;<span class="p">&amp;</span><span class="m">2</span> dbus-send --print-reply --session --dest<span class="o">=</span><span class="s2">"</span><span class="nv">$PLAYER</span><span class="s2">"</span> /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause</code></pre>
<p>C'est moins lisible, mais ça fait le job.</p>
<h4 id="toc-comparaison">Comparaison</h4>
<p>Avec GNU <a href="https://www.gnu.org/software/time">time</a>, je me suis amusé à comparer les trois implémentations (qui font la même chose, hein)</p>
<pre><code>Quoi          |  python | C      | shell
--------------+---------+--------+------
taille  code  |  0.8kB  | 5kB    | 0.6kB  
RAM           |  13MB   | 5MB    | 3MB
Vitesse       |  ~30 ms | &lt;10 ms | ~10ms
</code></pre>
<p>Sans surprise, python est plus lent et occupe plus en mémoire que l'implémentation en C, mais les ordres de grandeurs sont les mêmes et restent très raisonnables sur des architectures modernes (surtout comparé aux 3GB accaparés par firefox)</p>
<p>Je suis étonné le shell prenne si peu de RAM, faut peut être que je vérifie comment les pipes sont prises en compte par time…</p>
<h3 id="toc-la-suite">La suite</h3>
<p>Je suis content, après avoir copié les exécutables dans <code>~/.local/bin</code>, je n'ai plus à utiliser la souris pour changer de piste, et j'ai un peu appris un truc. La suite serait d'ajouter un filtre pour ne piloter que certains logiciels, soigner le rangement des sources python… mais ça sera pour la prochaine fois.</p>
<h4 id="toc-repo-git">Repo git</h4>
<p>Le code, c'est <a href="https://framagit.org/mabu/dbus-media-control">là</a></p>
<p>[1]: Aussi appelée liste des trucs que je ferai jamais<br/>
[2]: Oui, au singulier, c'était pas vraiment caché<br/>
[3]: Media Player Remote Interfacing Specification</p>
<div><a href="https://linuxfr.org/users/purplepsycho/journaux/piloter-firefox-mais-pas-que-avec-dbus.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139929/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/purplepsycho/journaux/piloter-firefox-mais-pas-que-avec-dbus#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>purplepsycho</name>
        </author>
    </entry>
    <entry>
        <title>Je code, je coop</title>
        <link href="https://yaal.coop/blog/interview-je-code-je-coop" />
        <id>https://yaal.coop/blog/interview-je-code-je-coop</id>
        <updated>2025-08-05T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Chez Yaal Coop, nous proposons régulièrement des temps d'échange informel avec des gens qu'on ne connaît pas encore, mais avec qui on pense partager des centres d'intérêt ou des valeurs.
Souvent ce sont des contributeurs de logiciels libres ou bien d'autres coopératives dans l'informatique.
Parmi elles, le mois dernier nous rencontrions <a href="https://www.hizkia.eu">Hizkia</a> une SCOP de Bayonne qui développe des outils industriels et de gestion,
<a href="https://hashbang.coop">Hashbang</a>, une SCOP de Pythonistes à Lyon,
et nos voisins de <a href="https://noesya.coop">Noesya</a> à Bordeaux, qui se spécialisent dans l'éco-conception et la réalisation de sites légers et accessibles. De belles rencontres chacune.</p>
<p>Noesya développe le projet « <a href="https://jecode.coop">Je code, je coop</a> », qui recense des interviews de développeurs dans des coopératives.</p>
<p><a href="https://jecode.coop"><img alt="Je code, je coop" src="https://yaal.coop/media/blog/articles/logo-jecode-jecoop.svg"/></a></p>
<p>Éloi a joué le jeu de l'interview, que vous pouvez consulter ici :</p>
<div style="padding: 56.25% 0 0 0;"></div>
<p>Et d'ailleurs en octobre 2024 on répondait à une interview écrite pour le site <a href="https://codecode.coop/temoignages/yaal-coop.html">codecode.coop</a>, qui est un projet similaire porté par <a href="https://www.codeursenliberté.fr">Codeurs en liberté</a></p>
<p><a href="https://codecode.coop"><img alt="Code code coop" src="https://yaal.coop/media/blog/articles/logo-codecodecoop.webp"/></a></p>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>PyLadiesCon 2025 − 5 au 7 décembre</title>
        <link href="https://discuss.afpy.org/t/pyladiescon-2025-5-au-7-decembre/2721" />
        <id>https://discuss.afpy.org/t/pyladiescon-2025-5-au-7-decembre/2721</id>
        <updated>2025-08-04T14:53:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello !</p>
<p>La <a href="https://2025.conference.pyladies.com/en/">PyLadiesCon 2025</a> a lieu en ligne, du 5 au 7 décembre.</p>
<p>Comme l’an dernier c’est multi-langues (anglais, espagnol, allemand, portugais, japonais, chinois) et multi-timezones.</p>
<p>Le CFP est ouvert jusqu’au 8 août : <a class="inline-onebox" href="https://pretalx.com/pyladiescon-2025/cfp">PyLadiesCon 2025 :: pretalx</a></p>
<p>Et l’appel à volontaires est aussi ouvert : <a href="https://portal.pyladies.com/">https://portal.pyladies.com/</a></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/pyladiescon-2025-5-au-7-decembre/2721/1">PyLadiesCon 2025</a></p>
<p>2025-12-05 00:00 (Europe/Paris) → 2025-12-07 23:45 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/pyladiescon-2025-5-au-7-decembre/2721">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>LangExtract : Un nouvel outil Google pour extraire des données structurées via les LLMs</title>
        <link href="https://github.com/google/langextract" />
        <id>https://github.com/google/langextract</id>
        <updated>2025-08-04T08:42:05Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Google dévoile LangExtract, une bibliothèque Python open source qui permet d’extraire des informations structurées à partir de textes bruts en utilisant les modèles de langage (LLMs). Cet outil se distingue par sa capacité de ‘source grounding’ précise et ses fonctionnalités de visualisation interactive, offrant aux développeur·se·s une solution robuste pour l’analyse et le traitement de données textuelles.</p>
<a href="https://news.humancoders.com/t/python/items/38009-langextract-un-nouvel-outil-google-pour-extraire-d"><img src="https://opengraph.githubassets.com/64a0754f5cae9734a51e9f64de4cdae467e4fc69b1a358c613da7a4fb7ef2fbb/google/langextract"/></a><hr/><a href="https://news.humancoders.com/t/python/items/38009-langextract-un-nouvel-outil-google-pour-extraire-d#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/38009-langextract-un-nouvel-outil-google-pour-extraire-d">LangExtract : Un nouvel outil Google pour extraire des données structurées via les LLMs</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Lemmings : l’histoire derrière le classique de DMA Design</title>
        <link href="https://www.olivierpons.fr/2025/07/25/lemmings-lhistoire-derriere-le-classique-de-dma-design/" />
        <id>https://www.olivierpons.fr/2025/07/25/lemmings-lhistoire-derriere-le-classique-de-dma-design/</id>
        <updated>2025-07-25T22:15:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Lemmings : L’histoire corrigée du jeu vidéo culte</h1>
<p>Il y a plusieurs décennies, un jeu a captivé des millions de joueurs et reste, à ce jour, considéré comme l’un des titres les plus originaux, addictifs et exigeants de l’histoire. Nous parlons de <em>Lemmings</em>, un jeu qui a connu d’innombrables adaptations et qui a indéniablement marqué son époque.</p>
<h2>L’origine des Lemmings</h2>
<p>Pour comprendre la genèse de <em>Lemmings</em>, il faut se tourner vers le studio de développement écossais <strong><a href="https://fr.wikipedia.org/wiki/Rockstar_North">DMA Design</a></strong> et son éditeur, <strong><a href="https://fr.wikipedia.org/wiki/Psygnosis">Psygnosis</a></strong>. L’idée du jeu est née d’une simple animation de petits personnages de 8×8 pixels créée par Mike Dailly, l’un des programmeurs de DMA, alors qu’il expérimentait pour un autre projet. C’est en voyant cette animation que son collègue, Russell Kay, s’est exclamé : « Il y a un jeu là-dedans ! » et a suggéré de nommer ces créatures « Lemmings ». <a href="https://en.wikipedia.org/wiki/David_Jones_(video_game_developer)">David Jones</a>, le fondateur de DMA Design, a ensuite dirigé le projet pour en faire le jeu que nous connaissons.</p>
<p>Le jeu est sorti le <strong><a href="https://www.jeuxvideo.com/news/976837/lemmings-une-version-modernisee-sur-ios-et-android-du-puzzle-game-mythique.htm">14 février 1991</a></strong> sur l’ordinateur Amiga, un jour de Saint-Valentin. Le succès fut immédiat et phénoménal : le jour de sa sortie, il s’est vendu à <strong>55 000 exemplaires</strong>, un record pour l’époque. Au total, on estime que la franchise a vendu entre <a href="https://www.pcgamesn.com/the-making-of-lemmings">15 et 20 millions d’exemplaires</a> sur toutes les plateformes confondues.</p>
<h2>Comment y jouer ?</h2>
<p>Le concept de <em>Lemmings</em> est simple en apparence : dans chaque niveau, des créatures aux cheveux verts apparaissent via une trappe et marchent inlassablement, se dirigeant vers une mort certaine si le joueur n’intervient pas. La mission est de leur assigner des compétences spécifiques pour modifier le décor et leur créer un passage sécurisé jusqu’à la sortie.</p>
<p>Pour cela, le joueur dispose d’un nombre limité de huit compétences, parmi lesquelles :</p>
<ul>
<li><strong>Grimpeur (Climber) :</strong> pour escalader les parois verticales.</li>
<li><strong>Flotteur (Floater) :</strong> pour utiliser un parachute et survivre aux chutes mortelles.</li>
<li><strong>Bloqueur (Blocker) :</strong> pour stopper les autres lemmings et les forcer à faire demi-tour.</li>
<li><strong>Bombe (Bomber) :</strong> pour faire exploser un lemming après un compte à rebours de cinq secondes.</li>
<li><strong>Constructeur (Builder) :</strong> pour bâtir des escaliers.</li>
<li><strong>Creuseur (Digger/Miner/Basher) :</strong> pour percer des tunnels à la verticale, en diagonale ou à l’horizontale.</li>
</ul>
<p>Le jeu original proposait <a href="https://fr.wikipedia.org/wiki/Lemmings_(jeu_vid%C3%A9o,_1991)">120 niveaux</a> répartis en quatre niveaux de difficulté : « Fun » (Amusant), « Tricky » (Délicat), « Taxing » (Éprouvant) et « Mayhem » (Chaos). Pour chaque niveau, il fallait sauver un certain pourcentage de lemmings dans le temps imparti.</p>
<h2>Qu’est-il arrivé aux Lemmings ?</h2>
<p>L’immense succès du jeu a entraîné une vague de portages sur la quasi-totalité des systèmes de l’époque : PC (MS-DOS), Super Nintendo, Game Boy, Mega Drive et bien d’autres. Des suites et extensions ont rapidement vu le jour, comme <strong><a href="https://en.wikipedia.org/wiki/Oh_No!_More_Lemmings">Oh No! More Lemmings</a></strong> dès 1991, qui ajoutait 100 niveaux inédits.</p>
<p>Mais que sont devenus ses créateurs ? DMA Design a continué sur sa lancée pour créer une autre franchise légendaire : <em>Grand Theft Auto</em> (GTA). Le studio a finalement été racheté et est aujourd’hui connu sous le nom de <strong><a href="https://fr.wikipedia.org/wiki/Rockstar_North">Rockstar North</a></strong>, un pilier de l’industrie du jeu vidéo.</p>
<p>Et qu’en est-il de la propriété intellectuelle (IP) du jeu ? Contrairement à une idée répandue, les droits n’ont pas été conservés par DMA Design. C’est l’éditeur, <strong><a href="https://fr.wikipedia.org/wiki/Psygnosis">Psygnosis</a>, qui détenait l’IP</strong>. Psygnosis a ensuite été <a href="https://en.wikipedia.org/wiki/Psygnosis#:~:text=In%201993%20the%20company%20was,PlayStation%20as%20primary%20reference%20hardware.">racheté par Sony en 1993</a>. C’est la raison pour laquelle les remakes et nouvelles versions de <em>Lemmings</em> sont apparus sur les consoles PlayStation, notamment sur <strong><a href="https://en.wikipedia.org/wiki/Lemmings_(2006_video_game)">PSP en 2006</a></strong>, sur PS Vita et même sur mobile, assurant ainsi la pérennité de ces créatures attachantes.</p>
<div class="footer">
        Cet article a été largement <a href="https://fr.eloutput.com/jeux-video/rapports/lemmings/" target="_blank">inspiré de l’article ici</a>, mais révisé et corrigé pour garantir l’exactitude des faits concernant l’un des jeux les plus influents de l’histoire.
    </div>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Auto-hébergement GitLab : bonne ou mauvaise idée ?</title>
        <link href="https://bearstech.com/blog/auto-hebergement-gitlab-bonne-ou-mauvaise-idee" />
        <id>https://bearstech.com/blog/auto-hebergement-gitlab-bonne-ou-mauvaise-idee</id>
        <updated>2025-07-22T15:30:13Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 31 juillet</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-31-juillet/2714" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-31-juillet/2714</id>
        <updated>2025-07-21T17:00:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Prochain meetup Python à Lyon : jeudi 31 juillet à partir de 18h au Malting Pot Part-Dieu !</p>
<p>Pour les sessions de l’été, pas de présentation au programme, mais des rencontres informelles <img alt=":sun:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/sun.png?v=14" title=":sun:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-31-juillet/2714/1">C’est l’été !</a></p>
<p>2025-07-31 18:00 (Europe/Paris) → 2025-07-31 22:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-31-juillet/2714">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Atelier en ligne (en anglais) pour apprendre à proposer une conf &lt;3 (PyLadiesCon)</title>
        <link href="https://discuss.afpy.org/t/atelier-en-ligne-en-anglais-pour-apprendre-a-proposer-une-conf-3-pyladiescon/2708" />
        <id>https://discuss.afpy.org/t/atelier-en-ligne-en-anglais-pour-apprendre-a-proposer-une-conf-3-pyladiescon/2708</id>
        <updated>2025-07-18T21:16:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Join our free online CFP workshop to craft a great proposal! <img alt=":purple_heart:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/purple_heart.png?v=14" title=":purple_heart:" width="20"/> <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=14" title=":snake:" width="20"/></p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="48" src="https://conference.pyladies.com/images/favicon.png" width="48"/>
<a href="https://conference.pyladies.com/2025-talks-workshop/" rel="noopener" target="_blank">conference.pyladies.com</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img class="thumbnail" height="388" src="https://conference.pyladies.com/images/posts/workshop-blogpost-1.png" width="690"/></div>
<h3><a href="https://conference.pyladies.com/2025-talks-workshop/" rel="noopener" target="_blank">Crafting a Conference Proposal Workshop for PyLadiesCon 2025</a></h3>
<p>This workshop is to demystify the CFP process and provide valuable tips on crafting a proposal</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>Ca peut intéresser des gens je pense ;o)</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/atelier-en-ligne-en-anglais-pour-apprendre-a-proposer-une-conf-3-pyladiescon/2708">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Mindiell</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114857168810264544" />
        <id>https://mamot.fr/@AFPy/114857168810264544</id>
        <updated>2025-07-15T13:08:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Only 6 days until the end of the Call for Proposals open until July 20, 2025 inclusive for PyConFR 2025 taking place from October 30 to November 2, 2025.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114857161973259573" />
        <id>https://mamot.fr/@AFPy/114857161973259573</id>
        <updated>2025-07-15T13:06:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Plus que 6 jours avant la fin du Call for proposals ouvert  jusqu'au 20 juillet 2025 inclus pour la PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Python 3.14 : découvrez les nouvelles fonctionnalités</title>
        <link href="https://docs.python.org/3.14/whatsnew/3.14.html#pep-779-free-threaded-python-is-officially-supported" />
        <id>https://docs.python.org/3.14/whatsnew/3.14.html#pep-779-free-threaded-python-is-officially-supported</id>
        <updated>2025-07-11T21:04:26Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Python 3.14 entre en phase beta et apporte son lot de nouveautés ! Explorez les changements majeurs et les améliorations qui seront disponibles dans cette prochaine version du langage de programmation. Un aperçu essentiel pour les développeur·se·s Python qui souhaitent rester à jour avec les dernières évolutions du langage.</p>
<a href="https://news.humancoders.com/t/python/items/37385-python-3-14-decouvrez-les-nouvelles-fonctionnalite"><img src="https://docs.python.org/3.14/_images/social_previews/summary_whatsnew_3.14_b08d5981.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/37385-python-3-14-decouvrez-les-nouvelles-fonctionnalite#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/37385-python-3-14-decouvrez-les-nouvelles-fonctionnalite">Python 3.14 : découvrez les nouvelles fonctionnalités</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>__init__.py vide ou pas</title>
        <link href="https://discuss.afpy.org/t/init-py-vide-ou-pas/2694" />
        <id>https://discuss.afpy.org/t/init-py-vide-ou-pas/2694</id>
        <updated>2025-07-10T18:09:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>bonjour,</p>
<p>Sur un projet existant que je rejoins, le fichier <code>__init__.py</code> contient l’import des différents modules.</p>
<p>D’après mes ressources, il serait préférable de laisser le <code>__init__.py</code> vide :</p>
<ol>
<li>
<p>C’est ce que l’on trouve dans le <a href="https://docs.python-guide.org/writing/structure/#packages" rel="noopener nofollow ugc">Hitchhiker’s Guide</a></p>
</li>
<li>
<p>Et dans cette vidéo de Brandon Rhodes à la conférence code::dive 2019 : <a href="https://www.youtube.com/watch?v=S0No2zSJmks" rel="noopener nofollow ugc">When Python Practices Go Wrong</a>  (44e minute)</p>
</li>
</ol>
<p>Voici ce qu’il dit :</p>
<blockquote>
<p><code>__init__.py</code> is a cost in the way of all the other modules that you might want to import.</p>
<p>Worse yet, for convenience, some <code>__init__.py</code> files import all their package’s module. That’s ruining the ability to cherry pick one thing you want. You can’t touch the package without waiting to load everything inside of it.</p>
<p>My advice, which is not what everyone would say, is to <strong>keep</strong> <code>__init__.py</code> <strong>empty of code</strong></p>
<p>I do understand that my users don’t want to have to import things manually from all dozen of my modules, so I have “an API module” that import all of the important classes so that you can say :</p>
<p><code>from skyfield.api import xxx, yyy, zzz</code></p>
</blockquote>
<p>J’ai retrouvé le fichier où il met ses imports : <a class="inline-onebox" href="https://github.com/skyfielders/python-skyfield/blob/master/skyfield/api.py" rel="noopener nofollow ugc">python-skyfield/skyfield/api.py at master · skyfielders/python-skyfield · GitHub</a></p>
<ol start="3">
<li>Cependant, un article très récent de <a href="https://realpython.com/python-init-py/#what-kind-of-code-should-i-put-in-__init__py" rel="noopener nofollow ugc">RealPython</a> propose exactement l’inverse. Est-ce qu’il y a des choses qui auraient changé ?</li>
</ol>
<p>Quel est votre avis ?</p>
<p>Je préfèrerai partir sur un <code>__init__.py</code> vide et cela m’intéresse de mettre les éventuels imports dans un fichier à part mais j’ai peur que ça me mette le bazar pour la documentation Sphinx (et sphinx-apidoc mais je vois un exclude pattern)</p>
<p>Merci d’avance pour vos conseils.</p>
<p>Françoise</p>
<p><small>14 messages - 7 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/init-py-vide-ou-pas/2694">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>fcodvpt</name>
        </author>
    </entry>
    <entry>
        <title>refonte mobilizon instances</title>
        <link href="https://linuxfr.org/users/steph1978/journaux/refonte-mobilizon-instances" />
        <id>https://linuxfr.org/users/steph1978/journaux/refonte-mobilizon-instances</id>
        <updated>2025-07-09T17:53:14Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-pourquoi">Pourquoi</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-les-raisons">Les raisons</a></li>
</ul>
</li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-design">Design</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-exploration">exploration</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-stack">Stack</a></li>
</ul>
</li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-productivit%C3%A9">Productivité</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-temps">Temps</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-lignes-de-code">Lignes de code</a></li>
</ul>
</li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-futur">Futur</a></li>
</ul>
<p>Ce journal raconte la ré-écriture de l'outil Mobilizon Instances suite au passage de témoin entre Framasoft et Kaihuri.</p>
<p><a href="https://instances.mobilizon.org/">Mobilizon Instances</a> est outil satellite de <a href="https://mobilizon.org">Mobilizon</a>, l'outil de gestion d'événements pour le Fediverse. Il s'agit du catalogue des instances que les utilisateurs ont bien voulu référencer (optin). Cela permet aux nouveaux venus de trouver une instance qui pourrait correspondre à leurs goûts.</p>
<p>Mobilizon Instances récolte aussi des données statistiques sur ces instances, quotidiennement, afin de les exposer.</p>
<h2 id="toc-pourquoi">Pourquoi</h2>
<p>Mais cet outil existe, tourne et son code est publié, pourquoi vouloir le ré-écrire, me direz vous ?</p>
<p>Soyons honnête : parce que j'en ai envie ! Mais cette envie est quand même motivée par certaines raisons liées à la maintenabilité et à l'évolutivité. Car je serai probablement le seul à y toucher. Les contributeurs sont toujours bienvenus mais nous préférons concentrer les efforts sur le produit principale.</p>
<h3 id="toc-les-raisons">Les raisons</h3>
<ul>
<li><p>Nodejs 8 ; le code n'a pas été retouché depuis des années et quand j'ai essayé de le faire tourner localement, je n'y suis pas arrivé. Soit je passe du temps à le mettre à niveau, soit j’investis ce temps dans autre chose</p></li>
<li><p>Nodejs ; je n'aime pas écrire du JS/TS, encore moins en backend. Je vois l'intérêt d'un framework web quand on a un front chiadé ; nous utilisons vuejs pour Mobilizon. Ici, le cas me paraît suffisamment simple pour s'en passer. Pour le backend, j'aime beaucoup Elixir ou Python, un peu Go, un jour peut être Rust.</p></li>
<li><p>Sqlpage ; j'ai déjà eu deux bonnes expériences avec SQLPage sur des projets perso. Quand on peut se permettre de rester proche des données et qu'on aime pas le frontend, c'est assez idéale. Je voulais mettre à profit cet avantage pour le cas présent.</p></li>
</ul>
<p>Quand je parle de bonne expérience, je parle autant des fonctionnalités de l'outil que de sa superbe documentation et de sa bienveillante communauté. Je ne crois pas être <a href="https://linuxfr.org/tags/sqlpage/public">seul</a>.</p>
<h2 id="toc-design">Design</h2>
<p>Le besoin est simple : deux écrans de consultation (liste, statistiques), un formulaire pour la proposition de nouvelle instance, et une tâche planifiée pour collecter et mettre à jour les données statistiques.</p>
<h3 id="toc-exploration">exploration</h3>
<p>L'auteur de sqlpage est toujours disponible pour une discussion sur son produit, pour peu qu'on lui amène un cas d'usage concret.</p>
<p>Et <a href="https://github.com/sqlpage/SQLPage/issues/947">cette discussion</a> confirme mon intuition : sqlpage ne gère pas et n'a pas vocation à gérer des tâches planifiées.<br/>
J'ai donc un petit dilemme: si je dois écrire une bonne partie du logiciel avec une autre solution, pourquoi ne pas l'écrire entièrement avec cette autre solution.</p>
<p>Je me lance un court moment dans l'écriture du premier écran - liste des instances - en python+fastapi+pypug. <a href="https://github.com/kakulukia/pypugjs?tab=readme-ov-file#example">Pypug</a> en particulier, est très sympa quand on préfère une représentation à la Yaml plutôt qu'à la XML. Nous utilisons Pug dans le <a href="https://framagit.org/kaihuri/mobilizon-event-importer">Mobilizon Importer</a>.</p>
<p>Mais je ne trouve pas la foi d'écrire tout le code nécessaire à la simple représentation du contenu d'une table SQLite dans un tableau HTML : template avec itération, route web, DAO pour lire les données ; alors que je sais que SQLPage le fait en <a href="https://sql-page.com/component.sql?component=table#:%7E:text=Example%202">quelques lignes</a>.</p>
<h3 id="toc-stack">Stack</h3>
<p>J'ai choisi:</p>
<ul>
<li>Sqlpage pour les pages web</li>
<li>SQLite pour la base de données</li>
<li>Python+scrapy pour la collecte des informations</li>
<li>Crond (alpine) pour l'ordonnancement des tâches</li>
<li>s6 pour la gestion des services</li>
<li>healthcheck.io pour l'observabilité</li>
<li>le tout empaqueté dans une image docker</li>
</ul>
<h2 id="toc-productivité">Productivité</h2>
<h3 id="toc-temps">Temps</h3>
<p>J'ai donc balancé tout ça dans un LLM et deux minutes plus tard … Non, je n'ai pas fait ça.</p>
<p>Mais, une fois n'est pas coutume, j'ai comptabilisé le temps que j'y ai passé. Je voulais me prouver que je ne passais pas plus de temps sur une ré-écriture que sur une remise à niveau.</p>
<p>Cela donne:</p>
<p><img alt="diagramme" src="https://img.linuxfr.org/img/68747470733a2f2f6d65726d6169642e696e6b2f7376672f70616b6f3a654e6f39547a74756844415176596f315452494a45422d62445337535a452d5264596f4a474c4143746d574d784761316c306e484f62685944464869616559393633336d427256704a484259726e57507a7363663071505158766c4245674675573231676c5664476b30615334574662323959344c30446f4a635a46546551696f4a475436725341534941616266676d445161624857397237564250782d3633373771587841366f566175325652367378666f544f365737417a5853446b624a5557705f59474f394774574565774d4237304a6666314d466e4f665154704c485f6b6b4153556b63767843614d4b455f304a464c4674466a696968735151555264453431774c32625a51536a64435075454735436b32446d2d784170674a4f395159767a63467834447a4b4c2d73325938555f707a4e7a3177467363706f426d477736565a345764775f476664564933307232615758766752584634414c5f42416a796e615a4978796d69575a717a4d5751525834437850797563545330396c586855565a6355396771386a4d303132666e38564c61715356755839423063626a6267/pako:eNo9TztuhDAQvYo1TRIJEB-bDS7SZE-RdYoJGLACtmWMxGa1l0nHObhYDFHiaeY9633mBrVpJHBYrnWPzscf0qPQXvlBEgFuW21glVdGk0aS4WFb29Y4L0DoJcZFTeQioJGT6rSASIAabfgmDQabHW9r7VBPx-6377qXxA6oVau2VR6sxfoTO6W7AzXSDkbJUWp_YGO9GtWEewMB70Jff1MFnOfQTpLH_kkASUkcvxCaMKE_0JFLFtFjiihsQQURdE41wL2bZQSjdCPuEG5Ck2Dm-xApgJO9QYvzcFx4DzKL-s2Y8U_pzNz1wFscpoBmGw6VZ4Wdw_GfdVI30r2aWXvgRXF4AL_BAjynaZIxymiWZqzMWQRX4CxPyucTS09lXhUVZcU9gq8jM012fn8VLaqSVuX9B0cbjbg" title="Source : https://mermaid.ink/svg/pako:eNo9TztuhDAQvYo1TRIJEB-bDS7SZE-RdYoJGLACtmWMxGa1l0nHObhYDFHiaeY9633mBrVpJHBYrnWPzscf0qPQXvlBEgFuW21glVdGk0aS4WFb29Y4L0DoJcZFTeQioJGT6rSASIAabfgmDQabHW9r7VBPx-6377qXxA6oVau2VR6sxfoTO6W7AzXSDkbJUWp_YGO9GtWEewMB70Jff1MFnOfQTpLH_kkASUkcvxCaMKE_0JFLFtFjiihsQQURdE41wL2bZQSjdCPuEG5Ck2Dm-xApgJO9QYvzcFx4DzKL-s2Y8U_pzNz1wFscpoBmGw6VZ4Wdw_GfdVI30r2aWXvgRXF4AL_BAjynaZIxymiWZqzMWQRX4CxPyucTS09lXhUVZcU9gq8jM012fn8VLaqSVuX9B0cbjbg"/></p>
<ul>
<li>design (1h) : le choix de la stack, le mise en place du projet, l’exploration</li>
<li>import data (4h) : j'ai perdu trop de temps sur des données Json, se méfier de <code>-&gt;</code> versus <code>-&gt;&gt;</code> en SQL</li>
<li>écrans (4h) : efficace, avec les composants table et chart, sans surprise</li>
<li>tâche planifiée (4h) : scrapy est top, vraiment peu de code à écrire, sans surprise</li>
<li>packaging (3h) : peaufiner un dockerfile prend toujours un peu de temps car il faut tester</li>
<li>déploiement (1h) : idem pour un docker compose</li>
<li>optimisation (4h) : la vue statistiques était trop lente à mon goût, j'ai refactoré</li>
</ul>
<p>Au total 21h, réparties sur une semaine et demie. Vous me direz ce que vous en pensez. Moi je trouve cela très correct.</p>
<h3 id="toc-lignes-de-code">Lignes de code</h3>
<p>Autre indicateur qui m'intéressait, la quantité de code dans l'optique, le moins à maintenir, le mieux. Ça veut dire déléguer une partie de la complexité aux dépendances ; c'est le but.</p>
<ul>
<li>vue : 93 lignes de SQL</li>
<li>job : 157 lignes de python, dont 41 liée à la migration de système</li>
<li>glu : 119 lignes de shell, dont 49 liée à la migration de système</li>
</ul>
<p>Soit 369 lignes de code, 279 si l'on ne prend pas en compte le code nécessaire à la transition depuis le système existant. À comparer aux 1737 lignes de code actuelle.</p>
<p>Ce chiffre est à prendre avec des pincettes car minimiser la quantité de code est un objectif qui me tient à cœur mais qui n'est pas forcément partagé. Et il manque encore des choses, qui vont venir faire augmenter ce chiffre.</p>
<p>J'attribue ces bons résultats - temps passé et quantité de code - au choix de la stack et à la bonne connaissance que j’en ai.</p>
<p>La stack prend en charge une bonne partie du travail à faire : Sqlpage pour la gestion des routes et la production du HTML+CSS+JS. Scrapy pour la gestion du parallélisme, du protocole HTTP et des ré-essais. Sans oublier s6 pour la gestion des services au sein du container.</p>
<h2 id="toc-futur">Futur</h2>
<p>Cette version réécrite va <a href="https://beta-instances.mobilizon.org/">tourner quelques temps</a> en parallèle de la version en production, avant une éventuelle bascule.</p>
<p>La vue liste mérite entre temps d'être peaufinée, avec probablement l'ajout d'un peu de styles.<br/>
Je dois aussi travailler sur le nettoyage des instances fantômes et optout, géré les défauts de réponse.</p>
<p>À ce stade, j'ai trouvé l'exercice très plaisant.</p>
<hr/>
<blockquote>
<p>Hep! pas si vite ! et le code alors ?</p>
</blockquote>
<p>Il est consultable <a href="https://git.zoocoop.com/setop/mobilizon_instances">ici</a>.</p>
<div><a href="https://linuxfr.org/users/steph1978/journaux/refonte-mobilizon-instances.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139702/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/steph1978/journaux/refonte-mobilizon-instances#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>steph1978</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114823303084121312" />
        <id>https://mamot.fr/@AFPy/114823303084121312</id>
        <updated>2025-07-09T13:36:01Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Only 12 days until the end of the Call for Proposals open until July 20, 2025 inclusive for PyConFR 2025 taking place from October 30 to November 2, 2025.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114823292815727711" />
        <id>https://mamot.fr/@AFPy/114823292815727711</id>
        <updated>2025-07-09T13:33:24Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Plus que 12 jours avant la fin du Call for proposals ouvert  jusqu'au 20 juillet 2025 inclus pour la PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Quam Facere, un gestionnaire de procédure IT (Ré-écriture)</title>
        <link href="https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it-re-ecriture" />
        <id>https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it-re-ecriture</id>
        <updated>2025-07-08T10:34:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h3 id="toc-avant-propos">Avant-propos</h3>
<p>Je tiens avant tout à m'excuser pour mon précédent journal dont la forme laissait grandement à désirer.</p>
<h3 id="toc-présentation-de-quam-facere-comment-faire-en-latin">Présentation de Quam Facere («Comment faire» en latin)</h3>
<p>Les procédures IT sont souvent complexes et, surtout dans le cas de la gestion de cluster, elles réclament une grande rigueur dans l'écriture (tant sur le fond que sur la forme) et l'exécution (opération).<br/>
Les rédacteurs s'appliquent souvent sur le fond (bien que l'on oubli souvent les vérifications à faire entre chaque étape) mais délaissent un peu la forme (les actions à exécutées sont parfois sous la forme de balise «code», d'autres fois sous formes de citation…), ce qui peut entraîner des oublis lors de l'exécution.<br/>
J'ai donc écrit Quam Facere pour essayer de limiter ces risques.<br/>
Quam Facere ne va pas exécuter automatiquement des procédures mais va proposer une mise en forme unifiée (dans le cas des exports) ou va proposer un déroulé séquentiel avec une validation de chaque étape dans le cadre de l'exécution d'une opération.<br/>
Étant ingénieur Linux et donc plus habitué de l'utilisation de Python, j'ai développé cette application Web en Python associé à Flask et SQLAlchemy.</p>
<h3 id="toc-fonctionnalités-clés">Fonctionnalités Clés</h3>
<ul>
<li>
<strong>Gestion de Procédures Détaillée</strong> : Supporte l'utilisation de variables et de logiques conditionnelles pour des procédures dynamiques (les tests de condition vont ensuite être intégrés à la commande à exécuter).</li>
<li>
<strong>Gestion des opérations</strong> : Permet le suivi de l'exécution des opérations</li>
<li>
<strong>Exportation de documents</strong> : divers formats, comme Mardown,PDf, Docx…</li>
<li>
<strong>Contrôle d'Accès Basé sur les Rôles (RBAC)</strong> : Assure une authentification et une autorisation sécurisées avec une gestion des équipes.</li>
<li>
<strong>Génération de Contenu Dynamique</strong> : Capacité de substituer des variables dans le contenu pour une flexibilité accrue.</li>
<li>
<strong>Gestion des Tâches</strong> : Découpe les procédures en étapes traçables pour une meilleure organisation.</li>
<li>
<strong>Internationalisation</strong> : Pour l'instant supporte l'anglais et le français.</li>
<li>
<strong>Compatibilité Base de Données</strong> : S'adapte aux divers systèmes gestion de bases de données pris en charge par SQLAlchemy, tels que SQLite, MySQL et PostgreSQL.</li>
</ul>
<h3 id="toc-avantages-et-cas-dutilisation">Avantages et Cas d'Utilisation</h3>
<p>Quam Facere vise à rationaliser les opérations IT complexes, à améliorer la collaboration d'équipe et à assurer la cohérence dans l'exécution des procédures. Ses cas d'utilisation incluent :</p>
<ul>
<li>La standardisation des procédures pour les équipes opérationnelles.</li>
<li>La documentation et l'exécution de la maintenance des serveurs pour l'administration système.</li>
<li>La gestion du déploiement et de la configuration dans les workflows DevOps.</li>
<li>Le maintien de pistes d'audit pour la conformité.</li>
<li>La fourniture de procédures structurées pour la formation et l'intégration des équipe</li>
</ul>
<h3 id="toc-installation-et-utilisation">Installation et utilisation</h3>
<h4 id="toc-venv"><strong>Venv</strong></h4>
<pre><code class="bash">git clone git.code.sf.net/p/quam-facere/code
<span class="nb">cd</span> code

python3 -m venv venv
<span class="nb">source</span> venv/bin/activate

<span class="c1"># For development run</span>
flask run

<span class="c1"># For Gunicorn wsgi run</span>
gunicorn -w <span class="m">4</span> -b <span class="s1">'0.0.0.0:5000'</span> qf:app</code></pre>
<h4 id="toc-docker"><strong>Docker</strong></h4>
<pre><code class="bash">sudo docker load -i -q https://sourceforge.net/projects/quam-facere/files/Docker_Images/qf.tar.gz
sudo docker run -p <span class="m">443</span>:5000 -v CONFIG_PATH:/etc/quam_facere -v INSTANCE_PATH:instance qf</code></pre>
<h3 id="toc-license">License</h3>
<p>Quam Facere est disponible sous license Apache 2.0</p>
<h3 id="toc-retour">Retour</h3>
<p>C'est une première version Alpha de cette application et de nombreux bogues doivent encore être présents.<br/>
Vous pouvez donc faire vos retours en ouvrant un ticket sur le dépôt Sourceforge</p>
<h3 id="toc-en-savoir-plus-et-tester-">En savoir plus et tester :</h3>
<ul>
<li>Le site : <a href="https://qf.spn109.fr">https://qf.spn109.fr</a>
</li>
<li>Le dépôt sur Sourceforge : <a href="https://sourceforge.net/projects/quam-facere/">https://sourceforge.net/projects/quam-facere/</a>
</li>
<li>La démo : <a href="https://qf-demo.spn109.fr/">https://qf-demo.spn109.fr/</a>
</li>
<li>Image Docker : <a href="https://sourceforge.net/projects/quam-facere/files/Docker_Images/qf.tar.gz">https://sourceforge.net/projects/quam-facere/files/Docker_Images/qf.tar.gz</a>
</li>
</ul>
<div><a href="https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it-re-ecriture.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139687/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it-re-ecriture#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>seraf1</name>
        </author>
    </entry>
    <entry>
        <title>Quam Facere, un gestionnaire de procédure IT</title>
        <link href="https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it" />
        <id>https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it</id>
        <updated>2025-07-04T08:47:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><em>Bonjour à tous,je tiens tout d'abord à préciser que le résumé ci-dessous à été généré par IA (je ne suis pas très doué pour ce genre d'exercice)</em></p>
<p>Quam Facere (Comment faire en latin): L'application open source pour la gestion des procédures IT<br/>
Nous sommes ravis de vous présenter Quam Facere, une application web complète et open source conçue pour rationaliser la gestion des procédures, des opérations et des workflows d'équipe dans les environnements IT. Développée avec Flask (Python), Quam Facere vise à offrir aux équipes une solution flexible et robuste pour standardiser et suivre leurs opérations quotidiennes.</p>
<p>Pourquoi Quam Facere ?</p>
<p>Face à la complexité croissante des infrastructures IT, la nécessité de procédures claires, traçables et exécutables devient primordiale. QF répond à ce besoin en proposant :</p>
<p>Gestion de procédures avancée : Créez, éditez et organisez vos procédures IT avec des variables dynamiques et une logique conditionnelle. Fini les documents figés et obsolètes !</p>
<p>Suivi d'exécution en temps réel : Lancez des opérations basées sur vos procédures et suivez leur progression étape par étape, en temps réel.</p>
<p>Contrôle d'accès basé sur les rôles (RBAC) : Gérez finement les permissions des utilisateurs au sein de structures d'équipes hiérarchiques, assurant sécurité et conformité.</p>
<p>Export de documentation : Générez automatiquement des documents (comme des présentations PPTX) à partir de vos procédures, facilitant la communication et l'audit.</p>
<p>Internationalisation : L'application est déjà disponible en Anglais et en Français.</p>
<p>Modularité et extensibilité : Construite sur des "blueprints" Flask, QF est conçue pour être facilement adaptable et extensible.</p>
<p>Pour qui ?</p>
<p>Que vous soyez une équipe d'opérations IT, un administrateur système, un ingénieur DevOps soucieux de standardiser les déploiements, ou que vous cherchiez à améliorer la conformité et la formation, Quam Facere offre une plateforme centralisée pour structurer et exécuter vos tâches.</p>
<p>Participez au projet !</p>
<p>Quam Facere est un projet libre et open source. Nous encourageons la communauté à explorer le code, remonter les problèmes, suggérer des fonctionnalités ou même contribuer directement au développement. Votre feedback est précieux !</p>
<p>Pour en savoir plus et tester Quam Facere :</p>
<ul>
<li>Site : <a href="https://qf.spn109.fr">Site</a>
</li>
<li>Code source : <a href="https://sourceforge.net/projects/quam-facere/">Dépôt GIT</a>
</li>
<li>Images Docker (prêtes à l'emploi) : <a href="https://sourceforge.net/projects/quam-facere/files/Docker%20Images/">Image Docker</a>
</li>
</ul>
<p>N'hésitez pas à me faire part de vos retours !</p>
<div><a href="https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139645/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/seraf1/journaux/quam-facere-un-gestionnaire-de-procedure-it#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>seraf1</name>
        </author>
    </entry>
    <entry>
        <title>Dumbphone et agenda</title>
        <link href="https://discuss.afpy.org/t/dumbphone-et-agenda/2678" />
        <id>https://discuss.afpy.org/t/dumbphone-et-agenda/2678</id>
        <updated>2025-06-29T18:07:35Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello la team dumbphone !</p>
<p>Je teste depuis peu un feature phone dont je ne citerai ni le modèle ni la marque pour ne pas faire de pub (c’est une bouse, la traduction en français est faite par une IA, le système est bogué de partout, mais je peux écouter la radio YEAH, et contrairement à mon pinephone je peux téléphoner).</p>
<p>Je savais qu’un peu d’openstreetmap et de GPS/Galileo/Glonass/GNSS/… me manquerai mais j’y étais préparé, ça ne marchait déjà pas (ou peu) sur mon pinephone.</p>
<p>Par contre ne pas avoir mon agenda synchronisé c’est bof. Ni mes contacts d’ailleurs.</p>
<p>Y’a de la 4G mais ils sont pas foutus d’implémenter un bête fetch ICS, ou une bête synchro caldav/carddav, en 2025. Ça fait 25 ans qu’on devait avoir des voitures volantes.</p>
<p>Le coup de gueule étant passé, j’ai implémenté un bête script <a href="https://git.afpy.org/mdk/ics_to_sms">ics-to-sms</a> qui shoot un SMS pour chaque VALARM trouvé dans un fichier ICS.</p>
<p>Ça fait le taff, enfin je crois, je verrai à l’usage.</p>
<p><small>6 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/dumbphone-et-agenda/2678">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114733217445718524" />
        <id>https://mamot.fr/@AFPy/114733217445718524</id>
        <updated>2025-06-23T15:46:03Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                PyConFR 2025 from October 30 to November 2, 2025<br />Call for proposals open until July 20, 2025 inclusive
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114733207345219470" />
        <id>https://mamot.fr/@AFPy/114733207345219470</id>
        <updated>2025-06-23T15:43:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025<br />Call for proposals ouvert  jusqu'au 20 juillet 2025 inclus
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Recherche développeur python / django - dimension devOps environnement Linux</title>
        <link href="https://discuss.afpy.org/t/recherche-developpeur-python-django-dimension-devops-environnement-linux/2669" />
        <id>https://discuss.afpy.org/t/recherche-developpeur-python-django-dimension-devops-environnement-linux/2669</id>
        <updated>2025-06-23T14:52:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je cherche pour mon client un développeur python / django expérimenté (à minima entre 5 et 8 ans d’expérience), avec une forte dimension devops sous environnement linux, pour un CDI en full remote.</p>
<p>Entreprise innovante, alliant cybersécurité et open source, ils ont dév leur propre solution utilisée par des organisations critiques.</p>
<p>Entreprise internationale, à taille humaine, réalise de manière régulière des sessions de travail sous forme de Hakathon afin de se réunir, dans des lieux sympa mêlant plaisir et coding.</p>
<p>Pour en savoir plus : <a href="mailto:doreen@pickmeup.fr">doreen@pickmeup.fr</a> ou bien 06 07 06 26 81</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/recherche-developpeur-python-django-dimension-devops-environnement-linux/2669">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>doreen</name>
        </author>
    </entry>
    <entry>
        <title>PyconFr 2025 : proposez des conférences !</title>
        <link href="https://discuss.afpy.org/t/pyconfr-2025-proposez-des-conferences/2668" />
        <id>https://discuss.afpy.org/t/pyconfr-2025-proposez-des-conferences/2668</id>
        <updated>2025-06-23T13:55:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à toutes et à tous <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=14" title=":slight_smile:" width="20"/></p>
<p><a href="https://cfp.pycon.fr/pyconfr-2025/" rel="noopener nofollow ugc">TL;DR; Proposez des conférences à la PyconFr</a></p>
<p>La PyConFr aura lieu du 30 octobre au 2 novembre 2025, à Lyon (dans le 9e).</p>
<p>L’appel à participation est en cours, il se clôture le 20 juillet en fin de journée. C’est dans moins d’un mois.</p>
<p>Les sujets peuvent être très techniques, pas trop techniques, pas du tout techniques. Je dois le préciser : vous pouvez proposer même si vous n’êtes pas expérimenté·e ou même (oui) si vous n’êtes pas développeur/euse ou technicien·ne.<br/>
On a des chercheurs qui font du Python, ou des data scientists. Mais aussi des graphistes, et des ingénieurs typographes. (Et des gens d’autres métiers aussi, et je vous assure que vous allez être surpris·es ; ça c’est du teasing totalement assumé, il faudra venir voir sur place.) Et on veut en entendre parler.</p>
<p>On veut aussi des sujets bas niveau, des présentations de packages utiles ou de fonctionnement du langage. On veut aussi des bretzels. Euh non pardon, ça c’était pour la PyconFr 2024.</p>
<p>Est-ce que vous avez découvert un truc récemment qui vous a changé la vie au boulot ? Un petit projet chouchou que vous voulez montrer à la terre entière ? Un machin que vous avez l’impression de réexpliquer tout le temps ? Super, allez-y, proposez. <img alt=":heart:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/heart.png?v=14" title=":heart:" width="20"/></p>
<p>N’hésitez pas à me contacter, ici ou sur Discord, pour discuter de votre sujet. Je peux vous aider à rédiger la réponse au CFP, j’en ai des dizaines à mon actif.</p>
<p>Après pour l’exercice en lui-même, je peux vous rassurer, vous aider à la préparation du discours et du support, j’ai une petite expérience d’accompagnement des jeunes et moins jeunes orateurices.</p>
<p>(Note pratique : le destin a un peu pété mes accès à Discord mais je vais essayer de les rétablir pour être <em>effectivement</em> joignable <img alt=":grimacing:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/grimacing.png?v=14" title=":grimacing:" width="20"/> )</p>
<p>Et la date de fin du CFP ici pour qu’elle soit affichée dans la liste des sujets :</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/pyconfr-2025-proposez-des-conferences/2668/1">Fin du CFP</a></p>
<p>2025-07-20 23:59 (Europe/Paris)</p>
</div>
<p><small>16 messages - 10 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/pyconfr-2025-proposez-des-conferences/2668">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>tut-tuuut</name>
        </author>
    </entry>
    <entry>
        <title>Spring 2025 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-printemps-2025" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-printemps-2025</id>
        <updated>2025-06-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://django-sesame.readthedocs.io">django-sesame</a></h2>
<p><em>Frictionless authentication with “Magic Links” for Django project</em></p>
<ul>
<li><a href="https://github.com/aaugustin/django-sesame/pull/113">Use f-string for exception messages</a></li>
</ul>
<h2><a href="https://magic-wormhole.readthedocs.io">Magic-Wormhole</a></h2>
<p><em>Get files from one computer to another, safely</em></p>
<ul>
<li>Remove 'u' prefix to strings for <a href="https://github.com/magic-wormhole/magic-wormhole/pull/636">the client</a> and <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/51">the relay server</a></li>
<li>Use classes directly instead of type() calls for <a href="https://github.com/magic-wormhole/magic-wormhole/pull/637">the client</a> and the <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/55">mailbox server</a></li>
<li>Update documentation (<a href="https://github.com/magic-wormhole/magic-wormhole/pull/638">remove details about python2 types</a>, <a href="https://github.com/magic-wormhole/magic-wormhole/pull/634">update minimal Python version in README.md</a> and <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/52">update tox URL</a>)</li>
<li><a href="https://github.com/magic-wormhole/magic-wormhole/pull/642">Replace formatted strings to f-strings</a></li>
</ul>
<h1><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h1>
<p><em>Collection of tools and libraries written for Sony's Playstation Portable (PSP) gaming console</em></p>
<ul>
<li><a href="https://github.com/pspdev/pspdev.github.io/pull/84">Fix CMake deprecation warnings</a></li>
<li><a href="https://github.com/pspdev/pspsdk/pull/271">Search improvement and link to constants</a> in documentation generated by Doxygen</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/273">Fix obsolete tags warnings</a> in documentation generated by Doxygen</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/275">Move generated documentation in dedicated directory</a> to avoid to delete a file involuntary</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/280">Add Code of Conduct in generated documentation</a> in documentation generated by Doxygen</li>
<li>Delete unused macros (<a href="https://github.com/pspdev/pspsdk/pull/281">1</a> and <a href="https://github.com/pspdev/pspsdk/pull/283">2</a>) and unused variables (<a href="https://github.com/pspdev/pspsdk/pull/284">1</a> et <a href="https://github.com/pspdev/pspsdk/pull/292">2</a>)</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/278">Only one constant definition</a></li>
<li><a href="https://github.com/pspdev/pspsdk/pull/291">Replace a statement by an assigment</a></li>
<li><a href="https://github.com/pspdev/pspsdk/pull/294">Fix goal of the file in the header comment</a></li>
</ul>
<h2><a href="https://api.github.com/repos/Bogdanp/dramatiq">dramatiq</a></h2>
<p><em>A fast and reliable background task processing library for Python 3.</em></p>
<ul>
<li><a href="https://github.com/Bogdanp/dramatiq/pull/688">Make the Prometheus dependency optional</a></li>
</ul>
<h2><a href="https://api.github.com/repos/pytest-dev/pytest-scim2-server">pytest-scim2-server</a></h2>
<p><em>SCIM2 server fixture for Pytest</em></p>
<p>We released <a href="https://pypi.org/project/pytest-scim2-server/#history">3 new versions</a> during this season.</p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-scim2-server/pull/1">Option to disable server logging</a></li>
</ul>
<h2><a href="https://api.github.com/repos/authlib/authlib">authlib</a></h2>
<p><em>The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.</em></p>
<p>We released <a href="https://pypi.org/project/authlib/#history">2 new versions</a> during this season.</p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/728">Fix invalid characters in error descriptions</a></li>
<li><a href="https://github.com/authlib/authlib/pull/729">Forbid URL fragments in redirection URIs</a></li>
<li><a href="https://github.com/authlib/authlib/pull/732">Allow <code>request_object_signing_alg_values_supported</code> to not contain 'none' and 'RS256'</a></li>
<li><a href="https://github.com/authlib/authlib/pull/733">Fix an issue when RFC9207 is enabled and the authorization response is not a 302</a></li>
<li><a href="https://github.com/authlib/authlib/pull/736">Use tox-uv and pre-commit-uv</a></li>
<li><a href="https://github.com/authlib/authlib/pull/739">Update Flask OAuth2 example to show error management</a></li>
<li><a href="https://github.com/authlib/authlib/pull/742">Example for RFC7591 <code>generate_client_registration_info</code> usage</a></li>
<li><a href="https://github.com/authlib/authlib/pull/743">Support for 'acr' and 'amr' claims in id_token</a></li>
<li><a href="https://github.com/authlib/authlib/pull/745">Remove deprecated <code>check_token_endpoint_auth_method</code> method</a></li>
<li><a href="https://github.com/authlib/authlib/pull/746">Use pytest style assertions in the test suite</a></li>
<li><a href="https://github.com/authlib/authlib/pull/748">Deprecate passing non <code>OAuth2Request</code> objects in <code>create_authorization_request</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/749">Implement RFC9101 JWT secured authentication requests (JAR)</a></li>
<li><a href="https://github.com/authlib/authlib/pull/750">Add codespell pre-commit</a></li>
<li><a href="https://github.com/authlib/authlib/pull/751">Fix missing 'state' param in authorization error responses</a></li>
<li><a href="https://github.com/authlib/authlib/pull/761">Fix <code>response_types</code> order unwanted strictness during dynamic client registration</a></li>
<li><a href="https://github.com/authlib/authlib/pull/762"><code>unsupported_response_type</code> errors are redirected</a></li>
<li><a href="https://github.com/authlib/authlib/pull/765">Update links to match the new repository URL</a></li>
<li><a href="https://github.com/authlib/authlib/pull/767">Skip <code>xc20p</code> algorithm unit tests when unavailable in cryptodome</a></li>
<li><a href="https://github.com/authlib/authlib/pull/774">OIDC userinfo endpoint support</a></li>
<li><a href="https://github.com/authlib/authlib/pull/776">Clarify the license permissions</a></li>
</ul>
<h2><a href="https://api.github.com/repos/authlib/joserfc">joserfc</a></h2>
<p><em>Implementations of JOSE RFCs in Python</em></p>
<ul>
<li><a href="https://github.com/authlib/joserfc/pull/39">Respect RFC6749 character set in error descriptions</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/43">Pre-commit configuration</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/46">Add a tox configuration</a></li>
</ul>
<h2><a href="https://api.github.com/repos/pytest-dev/pytest-iam">pytest-iam</a></h2>
<p><em>A lightweight and fully functional OAuth2 / OpenID Connect (OIDC) / SCIM server to be used in test suites.</em></p>
<p>We released <a href="https://pypi.org/project/pytest-iam/#history">3 new versions</a> during this season.</p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-iam/pull/4">Implement an embedded test client</a></li>
</ul>
<h2><a href="https://api.github.com/repos/authlib/otpauth">otpauth</a></h2>
<p><em>Implements two-step verification of HOTP/TOTP. Also known as one time password.</em></p>
<ul>
<li><a href="https://github.com/authlib/otpauth/pull/13">Handle non-ascii characters</a></li>
</ul>
<h2><a href="https://api.github.com/repos/Pylons/webtest">webtest</a></h2>
<p><em>Wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.</em></p>
<ul>
<li><a href="https://github.com/Pylons/webtest/pull/268">Strip HTML option tag text</a></li>
</ul>
<h2><a href="https://api.github.com/repos/15five/scim2-filter-parser">scim2-filter-parser</a></h2>
<p><em>A customizable parser/transpiler for SCIM2.0 filters</em></p>
<ul>
<li><a href="https://github.com/15five/scim2-filter-parser/pull/62">Fix a typo in the README</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<p>We released <a href="https://pypi.org/project/canaille/#history">8 new versions</a> during this season.</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/264">Better configuration defaults</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/265">Fix the phone number HTMX form raising a 400 error</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/267">Fix client JWT authentication for OIDC refresh_token and password grants</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/268">Ensure <code>id_token</code> has a <code>kid</code> header</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/269">Support for POST method at the Authorization endpoint</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/270">Implement OIDC login and consent prompts</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/271">Clients without scope defined don't restrict scopes for token emission</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/272">Fix userinfo 'address' claim</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/273">Implement RFC9101 JWT-Secured Authorization Request (JAR)</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/274">Implement the UserInfo endpoint with Authlib</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/276">Rework the JWKS configuration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/279">Authentication process overhaul</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/280">Fix the email field focus with HTMX</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant le printemps 2025</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-printemps-2025" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-printemps-2025</id>
        <updated>2025-06-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://django-sesame.readthedocs.io">django-sesame</a></h2>
<p><em>Authentication facile par des liens magiques pour tout projet Django</em></p>
<ul>
<li><a href="https://github.com/aaugustin/django-sesame/pull/113">Utilisation de f-string pour les messages d'exception</a></li>
</ul>
<h2><a href="https://magic-wormhole.readthedocs.io">Magic-Wormhole</a></h2>
<p><em>Obtenir des fichiers d'un ordinateur à l'autre, en sécurité</em></p>
<ul>
<li>Suppression des préfixes 'u' des chaînes de caractères pour <a href="https://github.com/magic-wormhole/magic-wormhole/pull/636">le client</a> et <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/51">le serveur relai</a></li>
<li>Utilisation directe de classes plutôt que des appels à <code>type()</code> pour <a href="https://github.com/magic-wormhole/magic-wormhole/pull/637">le client</a> et le <a href="https://github.com/magic-wormhole/magic-wormhole-mailbox-server/pull/55">serveur mailbox</a></li>
<li>Mise-à-jour de la documentation (<a href="https://github.com/magic-wormhole/magic-wormhole/pull/638">suppression de détails concernant les types de python2</a>, <a href="https://github.com/magic-wormhole/magic-wormhole/pull/634">mise-à-jour de la version minimale de Python dans le fichier README.md</a> et <a href="https://github.com/magic-wormhole/magic-wormhole-transit-relay/pull/52">mise-à-jour d'une URL</a>)</li>
<li><a href="https://github.com/magic-wormhole/magic-wormhole/pull/642">Remplacement de formatage de chaînes de caractères en f-strings</a></li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Ensemble d'outils et de bibliothèques pour la console PSP de Sony</em></p>
<ul>
<li><a href="https://github.com/pspdev/pspdev.github.io/pull/84">Correction d'alertes (deprecation warnings) produit par CMake</a></li>
<li><a href="https://github.com/pspdev/pspsdk/pull/271">Amélioration de la recherche et des liens vers des constantes</a> dans la documentation produite par Doxygen</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/273">Correction d'alertes (deprecation warnings) liées à des configurations obsolètes</a> dans la documentation produite par Doxygen</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/275">Déplacement de la documentation générée dans un répertoire dédié</a> pour éviter de supprimer un fichier involontairement</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/280">Ajout du Code de Conduite</a> dans la documentation produite par Doxygen</li>
<li>Suppression de macros inutilisées (<a href="https://github.com/pspdev/pspsdk/pull/281">1</a> et <a href="https://github.com/pspdev/pspsdk/pull/283">2</a>) et de variables inutilisées (<a href="https://github.com/pspdev/pspsdk/pull/284">1</a> et <a href="https://github.com/pspdev/pspsdk/pull/292">2</a>)</li>
<li><a href="https://github.com/pspdev/pspsdk/pull/278">Définition unique d'une constante</a></li>
<li><a href="https://github.com/pspdev/pspsdk/pull/291">Remplacement d'un test par une assignation</a></li>
<li><a href="https://github.com/pspdev/pspsdk/pull/294">Correction du but d'un fichier d'exemple dans le commentaire d'en-tête</a></li>
</ul>
<h2><a href="https://api.github.com/repos/Bogdanp/dramatiq">dramatiq</a></h2>
<p><em>Un exécuteur de tâches rapide et fiable pour Python 3</em></p>
<ul>
<li><a href="https://github.com/Bogdanp/dramatiq/pull/688">La dépendence à Prometheus est désormais facultative</a></li>
</ul>
<h2><a href="https://api.github.com/repos/pytest-dev/pytest-scim2-server">pytest-scim2-server</a></h2>
<p><em>Une fixture fournissant un serveur SCIM2 pour Pytest</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/pytest-scim2-server/#history">3 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-scim2-server/pull/1">Implémentation d'une option pour désactiver la journalisation du serveur</a></li>
</ul>
<h2><a href="https://api.github.com/repos/authlib/authlib">authlib</a></h2>
<p><em>Bibliothèque Python de gestion des identités et des accès</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/authlib/#history">2 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/authlib/authlib/pull/728">Correction de caractères invalides dans les descriptions des erreurs</a></li>
<li><a href="https://github.com/authlib/authlib/pull/729">Interdiction d'utiliser des fragments d'URL dans les URIs de redirection</a>.</li>
<li><a href="https://github.com/authlib/authlib/pull/732">'none' et 'RS256' ne sont plus des valeurs obligatoires pour <code>request_object_signing_alg_values_supported</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/733">Correction d'une erreur lorsque RFC9207 est activée et que la réponse à la requête d'authentification n'est pas une redirection</a></li>
<li><a href="https://github.com/authlib/authlib/pull/736">Utilisation de tox-uv et pre-commit-uv</a></li>
<li><a href="https://github.com/authlib/authlib/pull/739">Documentation sur la gestion des erreurs avec Flask et OAuth2</a></li>
<li><a href="https://github.com/authlib/authlib/pull/742">Documentation sur l'utilisation de la méthode <code>generate_client_registration_info</code> de la RFC7591</a></li>
<li><a href="https://github.com/authlib/authlib/pull/743">Support des paramètres 'acr' et 'amr' dans id_token</a></li>
<li><a href="https://github.com/authlib/authlib/pull/745">Suppression de la méthode dépréciée <code>check_token_endpoint_auth_method</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/746">Style d'assertions de Pytest dans les tests unitaires</a></li>
<li><a href="https://github.com/authlib/authlib/pull/748">Dépréciation de l'utilisation d'objets différents de <code>OAuth2Request</code> dans la méthode <code>create_authorization_request</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/749">Implémentation de la spécification <em>RFC9101 JWT secured authentication requests (JAR)</em></a></li>
<li><a href="https://github.com/authlib/authlib/pull/750">Ajout du pre-commit <em>codespell</em></a></li>
<li><a href="https://github.com/authlib/authlib/pull/751">Correction du paramètre 'state' manquant dans les erreurs de requête d'authentification</a></li>
<li><a href="https://github.com/authlib/authlib/pull/761">Correction de l'ordre des valeurs du paramètre <code>response_types</code></a></li>
<li><a href="https://github.com/authlib/authlib/pull/762">Les erreurs <code>unsupported_response_type</code> sont redirigées</a></li>
<li><a href="https://github.com/authlib/authlib/pull/765">Mise à jour des URLs pour pointer vers le nouveau dépôt</a></li>
<li><a href="https://github.com/authlib/authlib/pull/767">Les tests unitaires ignorent l'algorithme <code>xc20p</code> lorsqu'il n'est pas disponible dans cryptodome</a></li>
<li><a href="https://github.com/authlib/authlib/pull/774">Support du terminal OIDC <em>UserInfo</em></a></li>
<li><a href="https://github.com/authlib/authlib/pull/776">Clarify the license permissions</a></li>
</ul>
<h2><a href="https://api.github.com/repos/authlib/joserfc">joserfc</a></h2>
<p><em>Implémentation des normes JOSE en Python</em></p>
<ul>
<li><a href="https://github.com/authlib/joserfc/pull/39">Respect RFC6749 character set in error descriptions</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/43">Pre-commit configuration</a></li>
<li><a href="https://github.com/authlib/joserfc/pull/46">Add a tox configuration</a></li>
</ul>
<h2><a href="https://api.github.com/repos/pytest-dev/pytest-iam">pytest-iam</a></h2>
<p><em>Serveur OAuth2/OIDC léger pour suites de tests unitaires</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/pytest-iam/#history">3 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-iam/pull/4">Implémentation d'un client de tests embarqué</a></li>
</ul>
<h2><a href="https://api.github.com/repos/authlib/otpauth">otpauth</a></h2>
<p><em>Implémentation de mots de passe à usage unique en Python.</em></p>
<ul>
<li><a href="https://github.com/authlib/otpauth/pull/13">Support pour les caractères non-ascii</a></li>
</ul>
<h2><a href="https://api.github.com/repos/Pylons/webtest">webtest</a></h2>
<p><em>Bibliothèque de tests unitaires pour applications web</em></p>
<ul>
<li><a href="https://github.com/Pylons/webtest/pull/268">Suppression des espaces autour de la valeurs des balises <code>&lt;option&gt;</code></a></li>
</ul>
<h2><a href="https://api.github.com/repos/15five/scim2-filter-parser">scim2-filter-parser</a></h2>
<p><em>Un analyseur / transpileur personnalisable pour les filtres SCIM2.0</em></p>
<ul>
<li><a href="https://github.com/15five/scim2-filter-parser/pull/62">Correction d'une erreurs dans le fichier README</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Serveur d’identité et d'autorisations ultra-léger</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/canaille/#history">8 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/264">Implémentations de meilleurs valeurs de configuration par défaut</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/265">Correction d'une erreur sur la validation instantannée du champs « téléphone »</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/267">Correction de l'authentification par JWT des clients OIDC pour les flux <code>refresh_token</code> et <code>password</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/268">Tous les <code>id_token</code> ont une en-tête <code>kid</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/269">Support de la méthode POST sur le point terminal d'autorisation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/270">Implémentation des valeurs <code>login</code> et <code>consent</code> pour le paramètre OIDC <code>prompt</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/271">Les clients sans portée definie n'imposent pas de restriction sur la portée des jetons qu'ils émettent</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/272">Correction du paramètre 'address' du point terminal <em>UserInfo</em></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/273">Implémentation de la norme <em>RFC9101 JWT-Secured Authorization Request (JAR)</em></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/274">Implémentation du point terminal <em>UserInfo</em> avec Authlib</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/276">Refonte de la configuration JWKS</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/279">Refonte du processus d'authentification</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/280">Correction des problèmes de focus sur le champs « email »</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 30 juin</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-30-juin/2665" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-30-juin/2665</id>
        <updated>2025-06-20T14:54:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Le prochain meetup sur Lyon a lieu le lundi 30 juin à 19h!</p>
<p>Pour ce meetup nous serons accueillis par Wanadev Digital (métro Gare de Vaise), et <a class="mention" href="https://discuss.afpy.org/u/lize">@liZe</a> nous présentera des bonnes pratiques utiles lorsque l’on souhaite développer une bibliothèque Python et la partager <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=14" title=":snake:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-30-juin/2665/1">Tout autour d’une bibliothèque Python</a></p>
<p>2025-06-30 19:00 (Europe/Paris) → 2025-06-30 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-30-juin/2665">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Relance d&#39;un script</title>
        <link href="https://discuss.afpy.org/t/relance-dun-script/2664" />
        <id>https://discuss.afpy.org/t/relance-dun-script/2664</id>
        <updated>2025-06-19T06:34:13Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
j’ai parfois besoin de relancer un script python (environnement virtuel). J’ai un bouton pour le faire avec la fonction suivante d’associée:</p>
<pre><code class="lang-python">def rel():
	fen.quit()
	os.system("chemin_python"+__file__)
</code></pre>
<p>Y-a-t-il un moyen plus adéquat pour réaliser cela ?<br/>
Merci</p>
<p><small>9 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/relance-dun-script/2664">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Un paquet PyPi malveillant vole les secrets des utilisateurs de Chimera</title>
        <link href="https://linuxfr.org/users/alimentaire/liens/un-paquet-pypi-malveillant-vole-les-secrets-des-utilisateurs-de-chimera" />
        <id>https://linuxfr.org/users/alimentaire/liens/un-paquet-pypi-malveillant-vole-les-secrets-des-utilisateurs-de-chimera</id>
        <updated>2025-06-18T14:24:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.lemondeinformatique.fr/actualites/lire-un-package-pypi-malveillant-vole-les-secrets-des-utilisateurs-de-chimera-97185.html">https://www.lemondeinformatique.fr/actualites/lire-un-package-pypi-malveillant-vole-les-secrets-des-utilisateurs-de-chimera-97185.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139501/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/alimentaire/liens/un-paquet-pypi-malveillant-vole-les-secrets-des-utilisateurs-de-chimera#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Voltairine</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114704226953191286" />
        <id>https://mamot.fr/@AFPy/114704226953191286</id>
        <updated>2025-06-18T12:53:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Call for sponsors for PyConFR 2025<br />- support a free conference<br />- promotes your brand to the French Python community<br />- gain visibility
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114704218139048335" />
        <id>https://mamot.fr/@AFPy/114704218139048335</id>
        <updated>2025-06-18T12:51:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Appel à sponsors pour la PyConFR 2025 qui se déroule à Lyon. Avantages écrits :<br />- soutient une conférence gratuite<br />- met en avant votre marque auprès de la communauté francophone Python<br />- gain en visibilité
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Debian : 10 raisons qui en font la distribution de référence</title>
        <link href="https://bearstech.com/societe/blog/debian-10-raisons-qui-en-font-la-distribution-de-reference" />
        <id>https://bearstech.com/societe/blog/debian-10-raisons-qui-en-font-la-distribution-de-reference</id>
        <updated>2025-06-12T12:10:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>Kivy, ce framework python aux capacités insoupçonnées et méconnues</title>
        <link href="https://discuss.afpy.org/t/kivy-ce-framework-python-aux-capacites-insoupconnees-et-meconnues/2659" />
        <id>https://discuss.afpy.org/t/kivy-ce-framework-python-aux-capacites-insoupconnees-et-meconnues/2659</id>
        <updated>2025-06-09T10:55:37Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Le framework <strong>Kivy</strong> est un logiciel libre bénéficiant d’un développement actif, porté par des développeurs passionnés (aucun salarié). Il est encore peu, voire mal, connu du public francophone.</p>
<p>Fonctionnant sur toutes les plateformes, y compris celles disposant de peu de ressources, il est principalement connu pour le développement d’applications Android en Python. Pourtant, Kivy excelle dans bien d’autres domaines.</p>
<p>Pour le promouvoir auprès des francophones et parler du Kivy « graphique » que j’apprécie particulièrement, j’ai écrit quelques articles sur le sujet, publiés sur DVP, notamment : <a class="inline-onebox" href="https://www.developpez.net/forums/blogs/1443512-mpython-alaplancha/b10686/pourquoi-choisir-kivy-plutot-pygame-creation-jeux-graphiques-python/" rel="noopener nofollow ugc">Pourquoi choisir Kivy plutôt que Pygame pour la création de jeux graphiques en Python ? - Blogs - Forum du club des développeurs et IT Pro</a><br/>
et dernièrement<br/>
<a class="inline-onebox" href="https://www.developpez.net/forums/blogs/1443512-mpython-alaplancha/b10703/kivy-framework-python-aux-capacites-insoupconnees-meconnues/" rel="noopener nofollow ugc">Kivy, ce framework python aux capacités insoupçonnées et méconnues - Blogs - Forum du club des développeurs et IT Pro</a> .</p>
<p><small>26 messages - 8 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/kivy-ce-framework-python-aux-capacites-insoupconnees-et-meconnues/2659">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>fabien</name>
        </author>
    </entry>
    <entry>
        <title>PGlite : Testez vos applications Python avec PostgreSQL aussi facilement qu&#39;avec SQLite</title>
        <link href="https://github.com/wey-gu/py-pglite" />
        <id>https://github.com/wey-gu/py-pglite</id>
        <updated>2025-06-06T08:21:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez PGlite, une bibliothèque Python qui simplifie l’utilisation de PostgreSQL dans vos tests. Cette wrapper permet aux développeur·se·s d’intégrer PostgreSQL dans leurs tests unitaires avec la même simplicité que SQLite, facilitant ainsi le développement et les tests d’applications utilisant PostgreSQL comme base de données principale.</p>
<a href="https://news.humancoders.com/t/python/items/35930-pglite-testez-vos-applications-python-avec-postgre"><img src="https://repository-images.githubusercontent.com/996795316/518ac2a4-19ed-45bf-8143-67503e8e7ab1"/></a><hr/><a href="https://news.humancoders.com/t/python/items/35930-pglite-testez-vos-applications-python-avec-postgre#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/35930-pglite-testez-vos-applications-python-avec-postgre">PGlite : Testez vos applications Python avec PostgreSQL aussi facilement qu'avec SQLite</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Matthieu Segret</name>
        </author>
    </entry>
    <entry>
        <title>Rapport d’incident suite au ban du 30 avril 2025</title>
        <link href="https://discuss.afpy.org/t/rapport-d-incident-suite-au-ban-du-30-avril-2025/2657" />
        <id>https://discuss.afpy.org/t/rapport-d-incident-suite-au-ban-du-30-avril-2025/2657</id>
        <updated>2025-06-06T06:38:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Fin avril, une série d’incidents a abouti au ban d’une personne du serveur Discord de l’association.</p>
<p>Suivant la même démarche que les rapports de transparence des PyConFR, un rapport d’incident a été rédigé.</p>
<p>Il est disponible sur le dépôt git, avec tous les documents de l’AFPy : <a class="inline-onebox" href="https://git.afpy.org/AFPy/gestion/src/branch/master/rapports_incident/rapport_incident_30042025.pdf">gestion/rapports_incident/rapport_incident_30042025.pdf sur master - AFPy/gestion - La forge de l'AFPy</a>.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/rapport-d-incident-suite-au-ban-du-30-avril-2025/2657">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>ModuleNotFoundError: No module named &#39;pip._vendor.packaging&#39;</title>
        <link href="https://discuss.afpy.org/t/modulenotfounderror-no-module-named-pip-vendor-packaging/2656" />
        <id>https://discuss.afpy.org/t/modulenotfounderror-no-module-named-pip-vendor-packaging/2656</id>
        <updated>2025-06-05T14:31:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Pas la première fois que je tombe sur ce pb.</p>
<pre><code class="lang-python">(placement) ~ 15:16:17 &gt; pip3 install openpyxl
Traceback (most recent call last):
  File "/home/virt/placement/bin/pip3", line 5, in &lt;module&gt;
    from pip._internal.cli.main import main
  File "/home/virt/placement/lib/python3.12/site-packages/pip/_internal/cli/main.py", line 10, in &lt;module&gt;
    from pip._internal.cli.autocompletion import autocomplete
  File "/home/virt/placement/lib/python3.12/site-packages/pip/_internal/cli/autocompletion.py", line 9, in &lt;module&gt;
    from pip._internal.cli.main_parser import create_main_parser
  File "/home/virt/placement/lib/python3.12/site-packages/pip/_internal/cli/main_parser.py", line 7, in &lt;module&gt;
    from pip._internal.cli import cmdoptions
  File "/home/virt/placement/lib/python3.12/site-packages/pip/_internal/cli/cmdoptions.py", line 23, in &lt;module&gt;
    from pip._vendor.packaging.utils import canonicalize_name
ModuleNotFoundError: No module named 'pip._vendor.packaging'
</code></pre>
<p>J’ai googlé l’erreur, plein d’erreurs similaires, mais les explications partent dans tous les sens, et avec des différences de mise en oeuvre qui rendent inexploitables les autres solus proposées - si tant est que je les comprisse -<br/>
faut dire, je ne suis pas passé à venv, mais resté fidèle, à tort ou à raison, à mkvirtualenv.<br/>
je suis au début d’un développement, et ya plus d’un an que je n’avais rien développé.<br/>
Je vais essayer de varier les versions, à la fois python et virtualenv.</p>
<p><small>5 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/modulenotfounderror-no-module-named-pip-vendor-packaging/2656">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>pierre.imbaud</name>
        </author>
    </entry>
    <entry>
        <title>python-versions: quota BigQuery atteint</title>
        <link href="https://discuss.afpy.org/t/python-versions-quota-bigquery-atteint/2655" />
        <id>https://discuss.afpy.org/t/python-versions-quota-bigquery-atteint/2655</id>
        <updated>2025-06-04T08:37:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Je vous ai peut-être déjà spammé avec :</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="123" src="https://git.afpy.org/assets/img/favicon.svg" width="152"/>
<a href="https://git.afpy.org/mdk/python-versions" rel="noopener" target="_blank">La forge de l'AFPy</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img class="thumbnail" height="345" src="https://git.afpy.org/mdk/python-versions/-/summary-card" width="690"/></div>
<h3><a href="https://git.afpy.org/mdk/python-versions" rel="noopener" target="_blank">python-versions</a></h3>
<p>Studying Python release adoptions by looking at PyPI downloads</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>C’est mon projet™ qui génère des “jolis” graphes de l’usage de Pypi :</p>
<p><img alt="% of PyPI download by Python version" height="459" src="https://git.afpy.org/mdk/python-versions/media/branch/main/python-versions-lines.png" width="690"/></p>
<p>La donnée est sur Google BigQuery, jusque là je m’en sortais avec le quota gratuit.</p>
<p>Mais ça y est, faire une requête BigQuery sur un mois de donnée dépasse le quota gratuit. Juste une requête. Mais ça se comprend vite : PyPI c’est ~70 milliards de téléchargements par mois, donc boom.</p>
<p>Je pense qu’une solution serait de requêter par semaine plutôt que par mois. Voir par jour.</p>
<p>Ça dépassera toujours le quota, mais au lieu de planter dès la 1ere requête j’aurai des requêtes qui passeront, et j’imagine que j’aurai moins d’un mois de donnée par mois requêtable en utilisant le quota gratuit.</p>
<p>D’où mon appel à l’aide : qui serait motivé pour partager son quota gratuit, c’est à dire lancer le script de temps en temps et commit les données ?</p>
<p><small>6 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/python-versions-quota-bigquery-atteint/2655">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Re: [AFPy] [Python/Entraide] Reconnaissance vocale avec Whisper</title>
        <link href="https://discuss.afpy.org/t/re-afpy-python-entraide-reconnaissance-vocale-avec-whisper/2653" />
        <id>https://discuss.afpy.org/t/re-afpy-python-entraide-reconnaissance-vocale-avec-whisper/2653</id>
        <updated>2025-06-03T14:00:54Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous,</p>
<p>Merci à chacun pour vos contribution.</p>
<p>Le code que tu soumets pour ton Mac est hors de mes compétences.</p>
<p>Je sais faire en ligne de commande en passant le wav déjà créé, solution<br/>
directe et simple.</p>
<p>Par contre j’échoue à passer les “chunks” à la volée lus depuis l’objet<br/>
sounddevice.InData (solution avec les threads).</p>
<p>J’ai un doute : une solution  en Python voix vers texte se fait-elle<br/>
quasiment “en temps réel” ?</p>
<p>Je creuse.</p>
<p>Pierre Estrem</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/re-afpy-python-entraide-reconnaissance-vocale-avec-whisper/2653">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>estrem</name>
        </author>
    </entry>
    <entry>
        <title>Reconnaissance vocale avec Whisper</title>
        <link href="https://discuss.afpy.org/t/reconnaissance-vocale-avec-whisper/2648" />
        <id>https://discuss.afpy.org/t/reconnaissance-vocale-avec-whisper/2648</id>
        <updated>2025-06-01T20:18:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>J’ai été inscrit sur ce forum sous le pseudo “peterpan31” mais suite à<br/>
des piratages de mes adresses j’ai fait le choix d’acheter mon propre<br/>
nom de domaine et j’écris désormais sous le pseudo “estrem”.</p>
<p>J’ai découvert le projet Whisper pour réaliser de la reconnaissance<br/>
vocale vers texte :</p><aside class="onebox githubrepo">
<header class="source">
<a href="https://github.com/ggml-org/whisper.cpp" rel="noopener nofollow ugc" target="_blank">github.com</a>
</header>
<article class="onebox-body">
<div class="github-row">
<img class="thumbnail" height="344" src="https://opengraph.githubassets.com/14b890aa4395e1191b37cbb217f3ceba/ggml-org/whisper.cpp" width="690"/>
<h3><a href="https://github.com/ggml-org/whisper.cpp" rel="noopener nofollow ugc" target="_blank">GitHub - ggml-org/whisper.cpp: Port of OpenAI's Whisper model in C/C++</a></h3>
<p><span class="github-repo-description">Port of OpenAI's Whisper model in C/C++</span></p>
</div>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>
)Je suppose que le projet dessus correspond à du binaire (codage en c++).</p>
<p>On trouve sa version Python pour faire de la transcription “temps réel”<br/>
pâr exemple ici :</p><aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="16" src="https://www.tecmint.com/wp-content/uploads/2020/07/favicon.ico" width="16"/>
<a href="https://www.tecmint.com/whisper-ai-audio-transcription-on-linux/" rel="noopener nofollow ugc" target="_blank" title="07:51AM - 04 March 2025">Running Whisper AI for Real-Time Speech-to-Text on Linux – 4 Mar 25</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img class="thumbnail" height="325" src="https://www.tecmint.com/wp-content/uploads/2025/03/Whisper-AI-Speech-to-Text-on-Linux.png" width="690"/></div>
<h3><a href="https://www.tecmint.com/whisper-ai-audio-transcription-on-linux/" rel="noopener nofollow ugc" target="_blank">How to Use Whisper AI for Live Audio Transcription on Linux</a></h3>
<p>Whisper AI is an advanced automatic speech recognition (ASR) model developed by OpenAI that can transcribe audio into text with impressive accuracy.</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>Le sujet est passionnant, à fortiori pour moi puisque étant déficient<br/>
visuel je fais quelques développements pour cette communauté.</p>
<p>Connaissiez-vous, avez-vous pratiqué , car de mon côté je rencontre des<br/>
erreurs.</p>
<p>Cordialement</p>
<p><small>9 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/reconnaissance-vocale-avec-whisper/2648">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>estrem</name>
        </author>
    </entry>
    <entry>
        <title>Sur Clermont-Ferrand - Meetup le 12 juin</title>
        <link href="https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-12-juin/2640" />
        <id>https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-12-juin/2640</id>
        <updated>2025-05-31T16:10:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Vous êtes développeur Python et vous cherchez à pousser les limites de vos applications ? Vous entendez parler des bases de données orientées graphes et de leur potentiel, mais vous ne savez pas par où commencer ?</p>
<p>Ne cherchez plus ! Nous sommes ravis de vous inviter à notre événement exclusif :</p>
<p><strong>L’intégration de Neo4j dans une application Python</strong></p>
<p><img alt=":spiral_calendar:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/spiral_calendar.png?v=14" title=":spiral_calendar:" width="20"/> <strong>Date :</strong> Jeudi 12 juin<br/>
<img alt=":alarm_clock:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/alarm_clock.png?v=14" title=":alarm_clock:" width="20"/> <strong>Heure :</strong> 18h30 - 19h30<br/>
<img alt=":round_pushpin:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/round_pushpin.png?v=14" title=":round_pushpin:" width="20"/> <strong>Lieu :</strong> Clermont-Ferrand</p>
<p><strong>Ce que vous allez apprendre :</strong></p>
<ul>
<li><strong>Pourquoi Neo4j ?</strong> Comprenez les avantages uniques des graphes pour gérer des données connectées</li>
<li><strong>Les bases de l’intégration :</strong> Démarrer un projet Neo4j avec Python de A à Z.</li>
<li><strong>Cas d’usage concrets :</strong> Voyez comment des applications réelles tirent parti de Neo4j pour résoudre des problèmatiques.</li>
<li><strong>Bonnes pratiques et astuces :</strong> Évitez les pièges courants et optimisez vos performances.</li>
<li><strong>Q&amp;A en direct :</strong> Posez toutes vos questions à nos experts !</li>
</ul>
<p>Que vous soyez débutant avec les bases de données graphes ou que vous cherchiez à approfondir vos connaissances sur l’intégration Python, cet événement est fait pour vous. C’est une occasion unique d’apprendre, d’échanger et d’élargir vos horizons technologiques.</p>
<p><strong><img alt=":wrapped_gift:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/wrapped_gift.png?v=14" title=":wrapped_gift:" width="20"/> Bonus :</strong> Nous poursuivrons par un apéro afin de continuer les échanges</p>
<p>Le nombre de places est limité, alors ne manquez pas cette opportunité !</p>
<p><img alt=":backhand_index_pointing_right:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/backhand_index_pointing_right.png?v=14" title=":backhand_index_pointing_right:" width="20"/> J’ai pas le droit de mettre de lien donc allez sur le site meetup pyclermont <img alt=":wink:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/wink.png?v=14" title=":wink:" width="20"/></p>
<p>Nous avons hâte de vous y retrouver pour explorer ensemble les possibilités infinies de Neo4j et Python !</p>
<p>À très bientôt,</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-12-juin/2640">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>drigaudie</name>
        </author>
    </entry>
    <entry>
        <title>Javid : Recherche de mission freelance Python/Django</title>
        <link href="https://discuss.afpy.org/t/javid-recherche-de-mission-freelance-python-django/2627" />
        <id>https://discuss.afpy.org/t/javid-recherche-de-mission-freelance-python-django/2627</id>
        <updated>2025-05-31T07:11:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je m’appelle <strong>Javid</strong>, <strong>Lead Développeur Fullstack &amp; Ingénieur DevOps</strong> avec <strong>9 ans d’expérience</strong>, spécialisé dans l’<strong>expérience développeur</strong>, l’<strong>automatisation</strong> et la <strong>scalabilité des infrastructures</strong>. J’ai évolué aussi bien en startup que dans de grands groupes comme <strong>Safran</strong>.</p>
<p>Passionné par <strong>Django</strong>, j’ai développé plusieurs applications web avec ce framework. Je suis également un fervent adepte de <strong>Docker</strong>, que je considère indispensable pour le <strong>déploiement</strong> et le <strong>travail en équipe</strong>.</p>
<p>Je suis actuellement à la recherche d’une mission freelance, idéalement en <strong>full remote</strong>. Je peux également me déplacer <strong>1 jour par semaine sur Paris</strong>, si besoin.</p>
<p>Merci pour votre attention,</p>
<p><strong>Javid</strong><br/>
<img alt=":e_mail:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/e_mail.png?v=14" title=":e_mail:" width="20"/> <a href="mailto:javid.mougamadou2@gmail.com">javid.mougamadou2@gmail.com</a><br/>
<img alt=":link:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/link.png?v=14" title=":link:" width="20"/> <a href="https://www.linkedin.com/in/mougamadoujavid/" rel="noopener nofollow ugc">LinkedIn – mougamadoujavid</a></p>
<p><small>4 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/javid-recherche-de-mission-freelance-python-django/2627">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Javid</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114585708840194177" />
        <id>https://mamot.fr/@AFPy/114585708840194177</id>
        <updated>2025-05-28T14:32:40Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Erratum : les vidéos de la <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a> 2024 étaient déjà disponibles sur IndyMotion (<a href="https://indymotion.fr/c/pyconfr2024/videos" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">indymotion.fr/c/pyconfr2024/vi</span><span class="invisible">deos</span></a>), il s'agissait ici d'un référencement réalisé sur la plateforme PyVideo.</p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114585059351049864" />
        <id>https://mamot.fr/@AFPy/114585059351049864</id>
        <updated>2025-05-28T11:47:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Les vidéos de la <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a> 2024 sont désormais en ligne ! Vous pouvez les consulter via <a href="https://pyvideo.org/events/pycon-fr-2024.html" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">pyvideo.org/events/pycon-fr-20</span><span class="invisible">24.html</span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Sur Bordeaux − Meetup le 17 juin</title>
        <link href="https://discuss.afpy.org/t/sur-bordeaux-meetup-le-17-juin/2619" />
        <id>https://discuss.afpy.org/t/sur-bordeaux-meetup-le-17-juin/2619</id>
        <updated>2025-05-27T14:54:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>Premier meetup de l’année à <a class="hashtag-cooked" href="https://discuss.afpy.org/tag/bordeaux"><span class="hashtag-icon-placeholder"><svg class="fa d-icon d-icon-square-full svg-icon svg-node" xmlns="http://www.w3.org/2000/svg"><use></use></svg></span><span>bordeaux</span></a> le <span class="discourse-local-date">2025-06-17T16:30:00Z UTC</span></p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="32" src="https://secure.meetupstatic.com/next/images/general/favicon.ico" width="32"/>
<a href="https://www.meetup.com/py-bdx/events/308081760/" rel="noopener nofollow ugc" target="_blank">Meetup</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img class="thumbnail" height="338" src="https://secure.meetupstatic.com/photos/event/6/2/1/d/600_528205117.jpeg" width="600"/></div>
<h3><a href="https://www.meetup.com/py-bdx/events/308081760/" rel="noopener nofollow ugc" target="_blank">Bordeaux Python Meetup 2025.1, mar. 17 juin 2025, 18:30   | Meetup</a></h3>
<p>* *à 19:00 : **Marimo : des notebooks Python pour remplacer les notebooks Jupyter*** (Jean-Luc Charles, consultant IA et data processing)
* *à 19:30 : **Les descripteurs Py</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<ul>
<li><em>à 19:00 : <strong>Marimo : des notebooks Python pour remplacer les notebooks Jupyter</strong></em> (Jean-Luc Charles, consultant IA et data processing)</li>
<li><em>à 19:30 : <strong>Les descripteurs Python : maitrisez l’art du contrôle des attributs</strong></em> (Luis Iglesias Hernandez, machine learning engineer chez ACC)</li>
<li>Présentations suivies d’un moment convivial avec des pizzas et goodies</li>
</ul>
<p>Le meetup est ouvert à tou·te·s les pythonistes novices ou confirmé·e·s.</p>
<p>Nous serons reçu par SII Nouvelle Aquitaine dans ses locaux de Mérignac accessibles en tram A qui offrira des pizzas et goodies (adaptateur USB multi-formats).</p>
<p>Il est impératif de RSVP sur <a href="https://www.meetup.com/py-bdx/events/308081760/" rel="noopener nofollow ugc">meetup.com</a> au plus tard le <strong>13 juin</strong>.</p>
<p>Au plaisir de vous y croiser ! <img alt=":wine_glass:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/wine_glass.png?v=14" title=":wine_glass:" width="20"/></p>
<p><small>4 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-bordeaux-meetup-le-17-juin/2619">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>yoan</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114579443275615648" />
        <id>https://mamot.fr/@AFPy/114579443275615648</id>
        <updated>2025-05-27T11:59:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                PyConFR 2025 from October 30 to November 2, 2025<br />Call for proposals open until July 20, 2025 inclusive
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114579428737501482" />
        <id>https://mamot.fr/@AFPy/114579428737501482</id>
        <updated>2025-05-27T11:55:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025<br />Call for proposals ouvert  jusqu'au 20 juillet 2025 inclus
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Copie de fichier via cp</title>
        <link href="https://discuss.afpy.org/t/copie-de-fichier-via-cp/2616" />
        <id>https://discuss.afpy.org/t/copie-de-fichier-via-cp/2616</id>
        <updated>2025-05-24T08:16:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
ma question est surement plus du ressort de bash que de python…<br/>
Je cherche à copier un fichier AppImage dont la permission est mise à “executable” dans un autre répertoire qui comporte le même fichier mais dont la permission n’est pas cochée à “executable” histoire de voir ce qu’il se passe. J’utilise:<br/>
subprocess.call([‘cp’, ‘-f’, nom.AppImage, “/home/chemin/Bureau/”])<br/>
Il semble que la copie ait lieu (l’icone du fichier change provisoirement) mais la permission n’est pas passée à “executable” comme attendu.  Une explication ?</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/copie-de-fichier-via-cp/2616">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Relance des adhésions expirées</title>
        <link href="https://discuss.afpy.org/t/relance-des-adhesions-expirees/2609" />
        <id>https://discuss.afpy.org/t/relance-des-adhesions-expirees/2609</id>
        <updated>2025-05-19T14:15:43Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>Je viens de renouveler mon adhésion à l’AFPy, il y a-t-il des rappels lorsque l’adhésion touche à sa fin ? HelloAsso indique 34 membres ce qui me semble bien peu ^^</p>
<p>Je pense qu’il peut y avoir 2 types de rappels d’adhésion :</p>
<ul>
<li>des <strong>rappels automatiques</strong> : 2 rappels à un mois d’intervalle avant puis après la fin d’adhésion me semble bien pour rappeler aux étourdis (quasi tout le monde ?) qu’ils doivent réadhérer s’ils le souhaitent</li>
<li>des <strong>rappels manuels</strong> (surtout utile si les rappels automatique ont subi une panne) : il peut y avoir une campagne “<em>Vous étiez adhérent l’année en 202X, souhaitez-vous soutenir à nouveau nos actions pour 202Y ?</em>”</li>
</ul>
<p>Une fois la décision prise de faire des rappels et quand, il faut encore savoir comment, en particulier pour les envois automatiques car HelloAsso ne gère pas cette fonctionnalité.</p>
<p>Pour une autre asso qui utilise l’ERP Dolibarr, j’avais mis en place <a href="https://github.com/Dolibarr/dolibarr-integration-resources/tree/main/helloasso/members-sync-python-ci" rel="noopener nofollow ugc">une synchro des membres via une CI</a> qui retrace ensuite tout l’historique des cotisations de nos membres sur les années et permet de créer des rappels automatiques. Ca fait le taff depuis 2 ans chez nous mais c’est un peu lourd, et il y a de temps en temps des breaking changes sur les deux API donc il faut faire les modifs. Il faudrait idéalement que ce soit intégré en PHP à Dolibarr.</p>
<p><small>20 messages - 9 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/relance-des-adhesions-expirees/2609">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>yoan</name>
        </author>
    </entry>
    <entry>
        <title>Pourquoi NumPy peut être complexe pour les développeur·se·s Python</title>
        <link href="https://dynomight.net/numpy/" />
        <id>https://dynomight.net/numpy/</id>
        <updated>2025-05-17T10:58:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Une réflexion sur les défis d’apprentissage et d’utilisation de NumPy, la célèbre bibliothèque de calcul numérique pour Python. Cet article explore les difficultés couramment rencontrées par les développeur·se·s dans leur parcours d’apprentissage de cette bibliothèque essentielle pour le calcul scientifique et l’analyse de données.</p>
<a href="https://news.humancoders.com/t/python/items/35072-pourquoi-numpy-peut-etre-complexe-pour-les-develop"><img src="https://dynomight.net/img/numpy/attention.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/35072-pourquoi-numpy-peut-etre-complexe-pour-les-develop#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/35072-pourquoi-numpy-peut-etre-complexe-pour-les-develop">Pourquoi NumPy peut être complexe pour les développeur·se·s Python</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>[ANN] Nouvelle version Mémento Python 3 (v2.1.1) + changement hébergement</title>
        <link href="https://linuxfr.org/users/lolop/journaux/ann-nouvelle-version-memento-python-3-v2-1-1-changement-hebergement" />
        <id>https://linuxfr.org/users/lolop/journaux/ann-nouvelle-version-memento-python-3-v2-1-1-changement-hebergement</id>
        <updated>2025-05-17T10:03:10Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><em>passage d'un post de entrée forum en un journal (+ complément car entre temps j'ai fait un petit ajout)</em></p>
<p>Salut,</p>
<p>À l'occasion d'un changement dans l'hébergement, j'en ai profité pour remettre à jour le Mémento Python 3 (dont la dernière version 2.0.6 datait de juin 2017).</p>
<p>Il est dispo dorénavant sur <a href="https://py3memento.lisn.fr/">py3memento.lisn.fr</a> (et <a href="https://py3cheatsheet.lisn.fr/">py3cheatsheet.lisn.fr</a> pour la version anglaise).</p>
<p><strong>Modifications de la version 2.1.1 :</strong></p>
<ul>
<li>ajout de la directive <code>global</code> dans les définitions de fonctions.</li>
</ul>
<p><strong>Modifications de la version 2.1.0 :</strong></p>
<ul>
<li>affection, ajout opérateur morse (walrus) <code>:=</code>
</li>
<li>ajout de l'instruction <code>match</code> … <code>case</code>
</li>
<li>formatage de chaînes, bascule sur les <em>f-string</em> (remplacement aussi aux endroits où .format() apparaissait)</li>
<li>méthodes des chaînes, ajout de <code>.format()</code>, <code>.removeprefix()</code>, <code>.removesuffix()</code>
</li>
<li>boucle <code>for</code>, révision algo for sur index en utilisant <code>enumerate</code>, ajout de deux lignes sur les expressions d'itérables (<code>map</code> et <code>filter</code>) en programmation fonctionnelle</li>
<li>opérateurs de fusion <code>|</code> et de mise à jour <code>|=</code> des dictionnaires</li>
<li>réorganisation de la section indexation des séquences pour gagner de la place</li>
<li>signalisation <code>()</code> autour de <em>context managers</em> pour ouvrir plusieurs fichiers avec <code>with</code>
</li>
</ul>
<p>A+</p>
<p>Note : si vous hébergez une copie locale, pensez à la mettre à jour.</p>
<div><a href="https://linuxfr.org/users/lolop/journaux/ann-nouvelle-version-memento-python-3-v2-1-1-changement-hebergement.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139209/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/lolop/journaux/ann-nouvelle-version-memento-python-3-v2-1-1-changement-hebergement#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>lolop</name>
        </author>
    </entry>
    <entry>
        <title>PyConFR 2025 — à Lyon du 30 octobre au 2 novembre</title>
        <link href="https://zestedesavoir.com/billets/4870/pyconfr-2025-a-lyon-du-30-octobre-au-2-novembre/" />
        <id>https://zestedesavoir.com/billets/4870/pyconfr-2025-a-lyon-du-30-octobre-au-2-novembre/</id>
        <updated>2025-05-15T11:54:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Conférence annuelle organisée par la communauté Python francophone
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Nouvelle version Mémento Python 3 (v2.1.0) + changement hébergement</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/nouvelle-version-memento-python-3-v2-1-0-changement-hebergement" />
        <id>https://linuxfr.org/forums/programmation-python/posts/nouvelle-version-memento-python-3-v2-1-0-changement-hebergement</id>
        <updated>2025-05-15T09:04:58Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>À l'occasion d'un changement dans l'hébergement, j'en ai profité pour remettre à jour le Mémento Python 3 (dont la dernière version 2.0.6 datait de juin 2017).</p>
<p>Il est dispo dorénavant sur <a href="https://py3memento.lisn.fr/">py3memento.lisn.fr</a> (et <a href="https://py3cheatsheet.lisn.fr/">py3cheatsheet.lisn.fr</a> pour la version anglaise).</p>
<p>C'est la version 2.1.0, dans les modifications :</p>
<ul>
<li>affection, ajout opérateur morse (walrus) <code>:=</code>
</li>
<li>ajout de l'instruction <code>match</code> … <code>case</code>
</li>
<li>formatage de chaînes, bascule sur les <em>f-string</em> (remplacement aussi aux endroits où .format() apparaissait)</li>
<li>méthodes des chaînes, ajout de <code>.format()</code>, <code>.removeprefix()</code>, <code>.removesuffix()</code>
</li>
<li>boucle <code>for</code>, révision algo for sur index en utilisant <code>enumerate</code>, ajout de deux lignes sur les expressions d'itérables (<code>map</code> et <code>filter</code>) en programmation fonctionnelle</li>
<li>opérateurs de fusion <code>|</code> et de mise à jour <code>|=</code> des dictionnaires</li>
<li>réorganisation de la section indexation des séquences pour gagner de la place</li>
<li>signalisation <code>()</code> autour de <em>context managers</em> pour ouvrir plusieurs fichiers avec <code>with</code>
</li>
</ul>
<p>A+</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/nouvelle-version-memento-python-3-v2-1-0-changement-hebergement.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139190/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/nouvelle-version-memento-python-3-v2-1-0-changement-hebergement#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>lolop</name>
        </author>
    </entry>
    <entry>
        <title>Attaques DDoS : pourquoi tant de haine ?</title>
        <link href="https://bearstech.com/societe/blog/attaques-ddos-pourquoi-tant-de-haine" />
        <id>https://bearstech.com/societe/blog/attaques-ddos-pourquoi-tant-de-haine</id>
        <updated>2025-05-13T18:30:33Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 22 mai</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-22-mai/2602" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-22-mai/2602</id>
        <updated>2025-05-12T13:04:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Le prochain meetup Python sur Lyon a lieu le jeudi 22 mai !</p>
<p>Rendez-vous dès 19h dans les locaux de Lowit (métro Part-Dieu) où Yohann nous parlera de typage statique et d’Abstract Base Classes <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=14" title=":snake:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-22-mai/2602/1">Turn Python Into Java, Use abc</a></p>
<p>2025-05-22 19:00 (Europe/Paris) → 2025-05-22 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-22-mai/2602">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114494586639930680" />
        <id>https://mamot.fr/@AFPy/114494586639930680</id>
        <updated>2025-05-12T12:19:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Call for sponsors for PyConFR 2025<br />- support a free conference<br />- promotes your brand to the French Python community<br />- gain visibility
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114494574587216011" />
        <id>https://mamot.fr/@AFPy/114494574587216011</id>
        <updated>2025-05-12T12:16:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Appel à sponsors<br />- soutient une conférence gratuite<br />- met en avant votre marque auprès de la communauté francophone Python<br />- gain en visibilité
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Dans les coulisses de Python : Comment fonctionne async/await ?</title>
        <link href="https://tenthousandmeters.com/blog/python-behind-the-scenes-12-how-asyncawait-works-in-python/" />
        <id>https://tenthousandmeters.com/blog/python-behind-the-scenes-12-how-asyncawait-works-in-python/</id>
        <updated>2025-05-12T10:54:26Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Plongez dans les mécanismes internes de Python pour comprendre le fonctionnement d’async/await. Cet article technique explore comment la simple utilisation des mots-clés async et await transforme votre code en programme asynchrone, permettant aux développeur·se·s d’optimiser leurs applications en exécutant des tâches pendant les temps d’attente.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/34511-dans-les-coulisses-de-python-comment-fonctionne-as#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/34511-dans-les-coulisses-de-python-comment-fonctionne-as">Dans les coulisses de Python : Comment fonctionne async/await ?</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Nouveau livre sur Python et Numpy</title>
        <link href="https://discuss.afpy.org/t/nouveau-livre-sur-python-et-numpy/2601" />
        <id>https://discuss.afpy.org/t/nouveau-livre-sur-python-et-numpy/2601</id>
        <updated>2025-05-12T06:32:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour le forum</p>
<p>Je viens de faire publier sur <a href="http://amazon.fr" rel="noopener nofollow ugc">amazon.fr</a> la 2e édition de mon livre “Invitation au calcul numérique avec Python et Numpy” (en version kindle et brochée de 828 pages comprenant 1500 exemples). Ce livre est composé de trois parties, la première concerne une introduction à Python, la deuxième concerne Numpy et la dernière est orientée vers les mathématiques numériques (polynôme, matrice, intégrale) avec différentes méthodes (certaines n’avaient encore jamais été présentées en langue française). Je tiens préciser que l’IA n’a jamais été utilisée pour la rédaction, pourquoi ? j’en ai horreur et ne me sentirai pas légitime en tant qu’auteur.</p>
<p>En cas d’acquisition, je serai bien entendu ravi d’accueillir toutes critiques constructives (positives et négatives).</p>
<p>Peter</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/nouveau-livre-sur-python-et-numpy/2601">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>petermaths</name>
        </author>
    </entry>
    <entry>
        <title>Jupyter, notebooks quelle formations / vidéos.</title>
        <link href="https://discuss.afpy.org/t/jupyter-notebooks-quelle-formations-videos/2597" />
        <id>https://discuss.afpy.org/t/jupyter-notebooks-quelle-formations-videos/2597</id>
        <updated>2025-05-08T15:29:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde, j’essaie de me former a jupyter lab et j’ai un peu de mal a trouver un support qui me convienne.</p>
<p>Je suis navré le message suivant est assez confus, c’est lié au fait que j’ai bien l’impression de passer a coté de quelque chose mais je n’arrive pas a le nommer.</p>
<p>Reprennons :</p>
<p>Quand j’ai effleuré les notebooks c’etait encore des “notebook  ipythons” ou des notebooks jupyter, en gros un python plus sympa avec des couleurs plus la notion de cellule que j’avais aussi pu voir dans matlab a l’époque (un peu comme dans spyder).</p>
<p>Bref j’utilise parfois ipython pour de la mise au point :</p>
<ul>
<li>Je fais mes commandes puis des %save fichier.py je curette ensuite.</li>
<li>pour des scripts système parce qu’on peut facilement recuprer les sorties et interpoler dans des commances tyquement <code>fichiers =  ! ls</code> puis</li>
</ul>
<pre><code class="lang-python">for f in fichiers:
   ! mv  {f} {f.replace('mp3', 'csv')}
</code></pre>
<p>Quand je cherche des vidéos sur jupyter suis souvent assez déçu, on expliquer comment manier l’interface. Parfois des subtiltés sur l’environnement du lab, non pas que cela ne soit pas intéressant mais j’ai pas vraiment l’impression d’avancer.</p>
<p>Pour moi c’est un peu comme si on m’apprenait python sans me parler de <code>dir()</code> ou <code>__dict__</code> , <code>getattr</code> ni de inspect ni de itertools ou collections.</p>
<p>Comment faire des notebook propres et faciliter leur export ? / Partage ?<br/>
Versionner les notebooks  ?  Les bonnes pratiques ?<br/>
Bref tout un tas de question sur l’artisanat jupyteresque…</p>
<p><a href="https://www.youtube.com/watch?v=RFabWieskak" rel="noopener nofollow ugc">https://www.youtube.com/watch?v=RFabWieskak</a> Typiquement cette vidéo semble intéressante et est faite par des pointures  pourtant j’en sors assez frustré, je ne vois pas trop comment un.e debutant.e. va aller faire son propre widget (le sujet est abordé a la fin) .</p>
<p>Bref quelles seraient les connaissances fondamentales qu’une personne expérimentée en jupyterlab / notebook suggérerait de connaître. Les trucs simples qu’on oublie ou qu’on ne voit pas forcément au début.</p>
<p>Typiquement l’equivalent notebook de ceci : <a href="https://www.youtube.com/watch?v=OSGv2VnC0go" rel="noopener nofollow ugc">https://www.youtube.com/watch?v=OSGv2VnC0go</a> ou bien cela  <a href="https://www.youtube.com/watch?v=w5J_WrcjwR0" rel="noopener nofollow ugc">https://www.youtube.com/watch?v=w5J_WrcjwR0</a></p>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/jupyter-notebooks-quelle-formations-videos/2597">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>colin</name>
        </author>
    </entry>
    <entry>
        <title>Kivy : un cadriciel graphique unique en Python</title>
        <link href="https://linuxfr.org/news/kivy-un-cadriciel-graphique-unique-en-python" />
        <id>https://linuxfr.org/news/kivy-un-cadriciel-graphique-unique-en-python</id>
        <updated>2025-05-06T16:13:18Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Kivy est un cadriciel (framework) graphique, permettant de développer des interfaces tactiles (ou utilisable à la souris) sur toutes les plateformes, y compris mobiles. Il s'accompagne d'une suite de logiciels très pratiques que nous allons présenter ici.</p>
<p><img alt="logo Kivy" src="https://img.linuxfr.org/img/68747470733a2f2f617661746172732e67697468756275736572636f6e74656e742e636f6d2f752f343039373237333f733d32303026763d34/4097273?s=200&amp;v=4" title="Source : https://avatars.githubusercontent.com/u/4097273?s=200&amp;v=4"/></p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/102818" hreflang="en" title="https://kivy.org/">site officiel</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/112078" hreflang="en" title="https://github.com/kivy-garden">Kivy Garden (extensions)</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/112079" hreflang="en" title="https://github.com/kivymd">KivyMD</a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/115594" hreflang="fr" title="https://ressources.labomedia.org/les_pages_kivy_en_details">Un très bon point d'entrée en français (merci chyek)</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-kivy-bo%C3%AEte-%C3%A0-outils-graphique-multi-plateformes">Kivy : boîte à outils graphique multi-plateformes</a></li>
<li>
<a href="https://linuxfr.org/tags/python/public.atom#toc-kv-interface-graphique-en-d%C3%A9claratif">kv : interface graphique en déclaratif</a><ul>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-les-propri%C3%A9t%C3%A9s">Les propriétés</a></li>
</ul>
</li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-plyer-acc%C3%A9der-facilement-aux-fonctionnalit%C3%A9s-mat%C3%A9rielles-de-votre-appareil">Plyer : accéder facilement aux fonctionnalités matérielles de votre appareil</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-python-for-android-utiliser-python-sur-android">Python For Android : utiliser Python… sur Android</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-kivy-for-ios-d%C3%A9ployez-sur-les-appareils-apple">Kivy for iOS : déployez sur les appareils Apple</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-pyjnius--utiliser-lapi-java-android-depuis-python">Pyjnius : utiliser l’API Java Android depuis Python</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-kivymd-des-widgets-material-design">KivyMD, des widgets Material Design</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-quelques-limitations">Quelques limitations</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-conclusion">Conclusion</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-une-note-dhistoire">Une note d’histoire</a></li>
</ul>
<h2 id="toc-kivy-boîte-à-outils-graphique-multi-plateformes">Kivy : boîte à outils graphique multi-plateformes</h2>
<p>Kivy permet de créer des interfaces graphiques naturellement adaptées aux écrans tactiles (mais qui restent utilisables sur un environnement de bureau traditionnel, à la souris et sans écran tactile). Il est écrit principalement en Python mais les parties critiques sont écrites en <a href="https://cython.org/">Cython</a>, ce qui lui permet d’avoir de bonnes performances.</p>
<p>Une interface Kivy peut s’écrire de deux façons (ou, plus couramment, par une combinaison de ces deux façons) : en Python directement, ou via <code>kv</code>, une syntaxe déclarative dont nous parlons plus bas.</p>
<p>Pour vous donner une idée, voici un exemple de <code>hello world</code> repris du site officiel de Kivy :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">kivy.app</span> <span class="kn">import</span> <span class="n">App</span>
<span class="kn">from</span> <span class="nn">kivy.uix.button</span> <span class="kn">import</span> <span class="n">Button</span>

<span class="k">class</span> <span class="nc">TestApp</span><span class="p">(</span><span class="n">App</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">build</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">Button</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="s1">'Hello World'</span><span class="p">)</span>

<span class="n">TestApp</span><span class="p">()</span><span class="o">.</span><span class="n">run</span><span class="p">()</span></code></pre>
<p>Ce qui donnera :<br/>
<img alt="capture d’écran du hello world" src="https://img.linuxfr.org/img/68747470733a2f2f6b6976792e6f72672f696d616765732f68656c6c6f776f726c642e706e67/helloworld.png" title="Source : https://kivy.org/images/helloworld.png"/></p>
<p>Une interface est composée de « widgets » agencés via des « <a href="https://kivy.org/doc/stable/gettingstarted/layouts.html">layouts</a> ». Certains widgets permettent de facilement mettre en place des composants communs de nos jours, comme par exemple le widget <a href="https://kivy.org/doc/stable/api-kivy.uix.carousel.html">Carousel</a> :<br/>
<img alt="capture d’un widget Carousel" src="https://img.linuxfr.org/img/68747470733a2f2f6b6976792e6f72672f646f632f737461626c652f5f696d616765732f6361726f7573656c2e676966/carousel.gif" title="Source : https://kivy.org/doc/stable/_images/carousel.gif"/></p>
<p>D’autre part, Kivy fournit des outils qui simplifient la vie du développeur ou de la développeuse, en particulier <a href="https://kivy.org/doc/stable/api-kivy.properties.html">un système de propriétés</a> (à ne pas confondre avec les propriétés Python) qui permet de mettre automatiquement l’interface à jour quand elles sont modifiées, ou de facilement attacher une fonction de rappel (« callback »), voir plus bas pour un exemple simple. On peut aussi citer <a href="https://kivy.org/doc/stable/api-kivy.animation.html">un mécanisme d’animations</a> très pratique et efficace.</p>
<h2 id="toc-kv-interface-graphique-en-déclaratif">kv : interface graphique en déclaratif</h2>
<p>kv est un langage permettant de décrire des interfaces, il met à profit les propriétés mentionnées plus haut et l’interface va se mettre à jour automatiquement quand des propriétés utilisées dans kv sont modifiées.</p>
<p>Reprenons le hello world vu plus haut, et faisons-le avec kv:</p>
<pre><code>Widget:
    Button:
        text: "Hello World"
</code></pre>
<p>Plutôt simple non ?<br/>
Le code kv est généralement mis dans des fichiers séparés avec l’extension <code>.kv</code>.</p>
<h3 id="toc-les-propriétés">Les propriétés</h3>
<p>Kivy a donc un concept de propriété, qui permettent la liaison de données bidirectionnelles (two-way data binding), ou en d’autres termes de facilement avoir l’état mis à jour entre le code python et l’interface décrite dans le fichier <code>kv</code>. C’est à l’usage très pratique et facile.</p>
<p>Un exemple va sans doute aider à comprendre.</p>
<p>Commençons par faire un environnement virtuel Python avec Kivy:</p>
<pre><code class="sh">$ mkdir demo

$ <span class="nb">cd</span> demo

$ python -m venv env

$ <span class="nb">source</span> env/bin/activate

$ pip install kivy</code></pre>
<p>Ensuite créez le fichier <code>demo.py</code> suivant :</p>
<pre><code class="python"><span class="kn">from</span> <span class="nn">kivy.app</span> <span class="kn">import</span> <span class="n">App</span>
<span class="kn">from</span> <span class="nn">kivy.uix.boxlayout</span> <span class="kn">import</span> <span class="n">BoxLayout</span>
<span class="kn">from</span> <span class="nn">kivy.properties</span> <span class="kn">import</span> <span class="n">NumericProperty</span>

<span class="k">class</span> <span class="nc">CompteurWidget</span><span class="p">(</span><span class="n">BoxLayout</span><span class="p">):</span>
    <span class="n">compteur</span> <span class="o">=</span> <span class="n">NumericProperty</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">increment</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">compteur</span> <span class="o">+=</span> <span class="mi">1</span>

<span class="k">class</span> <span class="nc">DemoApp</span><span class="p">(</span><span class="n">App</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">build</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">CompteurWidget</span><span class="p">()</span>

<span class="n">DemoApp</span><span class="p">()</span><span class="o">.</span><span class="n">run</span><span class="p">()</span></code></pre>
<p>Et maintenant, dans le même répertoire, ajoutez le fichier <code>demo.kv</code> suivant, ce dernier sera automatiquement découvert par Kivy parce qu’il s’appelle comme notre application (<code>DemoApp</code>) sans le suffixe <code>App</code> et en minuscule :</p>
<pre><code>
&lt;CompteurWidget&gt;:
    orientation: 'vertical'
    padding: 20

    Label:
        text: str(root.compteur)
        font_size: 30

    Button:
        text: "Incrémenter"
        on_press: root.increment()
</code></pre>
<p>Il ne nous reste plus qu’à lancer le programme :</p>
<pre><code class="sh">python demo.py</code></pre>
<p>Et à admirer :</p>
<p><img alt="capture d’écran du programme de démo" src="https://img.linuxfr.org/img/68747470733a2f2f706172746167652e6a616262657266722e6f72672f30363831333639362d333162652d376461382d613334302d3262343965386133653166342f636170747572655f64656d6f2e706e67/capture_demo.png" title="Source : https://partage.jabberfr.org/06813696-31be-7da8-a340-2b49e8a3e1f4/capture_demo.png"/></p>
<p>Le label se met automatiquement à jour quand le compteur <code>compteur</code> est incrémenté.</p>
<p>La lectrice ou le lecteur assidu de DLFP pourra faire un <a href="https://linuxfr.org/wiki/taptempo">TapTempo</a> en exercice.</p>
<p><strong>Note</strong>: Ne vous arrêtez pas au fait que l’UI est un peu "moche" par défaut, il y a des extensions beaucoup plus attractives (cf. <code>KivyMD</code> plus bas), et il est très facile de personnaliser l’interface et d’en faire une très belle en modifiant un peu ses fichiers <code>.kv</code>.</p>
<h2 id="toc-plyer-accéder-facilement-aux-fonctionnalités-matérielles-de-votre-appareil">Plyer : accéder facilement aux fonctionnalités matérielles de votre appareil</h2>
<p>Plyer est une bibliothèque permettant d’accéder à nombre de fonctions utiles de manière indépendante de la plateforme. Ainsi vous avez une API commune pour afficher une notification, demander l’état de la batterie, faire vibrer l’appareil, faire de la synthèse vocale de texte (« text-to-speech »), ouvrir un fichier avec le dialogue natif de la plateforme, etc.</p>
<p>Bien que développé par la même équipe que Kivy, ce paquet est utilisable indépendamment et est donc particulièrement utile pour n’importe quel projet multi-plateformes. Référez-vous <a href="https://github.com/kivy/plyer">à la page du projet</a> pour avoir un tableau des fonctionnalités supportées selon les plateformes, et à <a href="https://plyer.readthedocs.io/en/latest/">la documentation</a> pour plus de détails.</p>
<h2 id="toc-python-for-android-utiliser-python-sur-android">Python For Android : utiliser Python… sur Android</h2>
<p>Si vous souhaitez distribuer votre application sur Android, vous allez devoir avoir une version de Python compilée pour cette plateforme, ainsi que de tous les paquets nécessitant une compilation.</p>
<p>C’est le rôle de Python pour Android, qui est une collection d’outils qui s’appuient sur l’Android SDK pour permettre d’utiliser Kivy ou d’autre paquets Python sur Android, et ainsi faire votre propre distribution Python.</p>
<p>Si vous utilisez un paquet qui n’est pas en pur Python (c’est-à-dire qu’il y a des parties à compiler) et qui n’est pas encore disponible ou qui l’est mais dans une version trop ancienne, vous pouvez écrire ou mettre à jour des « recettes » (<em>recipes</em> en anglais) qui indiquent comment compiler. Référez-vous à <a href="https://python-for-android.readthedocs.io/en/latest">la documentation</a> pour voir comment faire.</p>
<p>Notez toutefois qu’il y a une pénalité à utiliser du Python par rapport à une application dans un langage compilé : il faut charger l’interprète au démarrage, et au tout premier lancement de votre application (et uniquement au premier) il y a aura une phase de décompression de vos fichiers. En dehors de ces petits inconvénients, ça fonctionne très bien.</p>
<p>Là encore, le projet est indépendant de Kivy et peut être utilisé avec un autre cadriciel.</p>
<h2 id="toc-kivy-for-ios-déployez-sur-les-appareils-apple">Kivy for iOS : déployez sur les appareils Apple</h2>
<p>À l’instar d’Android, l’équipe de Kivy fournit les outils pour faire votre distribution Python pour iOS.</p>
<p>Il vous faudra posséder une machine Apple pour les utiliser, à cause des restrictions imposées par cette plateforme (ceci n’est pas spécifique à Kivy pour iOS, mais s’applique à tous les outils pour développer sur iOS).</p>
<p>Ainsi avec une seule base de code (et après avoir passé un peu de temps pour configurer correctement les outils de compilation), vous pouvez déployer votre application Kivy/Python sur toutes les plateformes majeures (hormis le web, pour lequel il existe d’autres options comme <a href="https://brython.info/">Brython</a>, <a href="https://pyodide.org/en/stable/">Pyodide</a> ou <a href="https://pyscript.net/">PyScript</a>, mais c’est un sujet pour une autre dépêche).</p>
<h2 id="toc-pyjnius--utiliser-lapi-java-android-depuis-python">Pyjnius : utiliser l’API Java Android depuis Python</h2>
<p>Parfois l’utilisation de Plyer mentionné plus haut et de la bibliothèque standard Python ne suffisent pas, et vous avez besoin d’accéder à l’API d’Android, mais cette dernière est faite pour être utilisée avec Java ou Kotlin.</p>
<p>Pour pouvoir utiliser l’API d’Android depuis Python, <a href="https://github.com/kivy/pyjnius">PyJNIus</a> est disponible. Ce paquet permet d’accéder aux classes Java comme à des classes Python en utilisant JNI (« Java Native Interface » ou « Interface Native de Java »).</p>
<p>Ce paquet fournit une méthode <code>autoclass</code> qui convertit automatiquement une classe Java en Python, c’est très facile à utiliser et souvent suffisant pour les cas simples.</p>
<h2 id="toc-kivymd-des-widgets-material-design">KivyMD, des widgets Material Design</h2>
<p>KivyMD n’est pas un projet officiel de l’équipe Kivy, mais <a href="https://github.com/kivymd/KivyMD">un projet tiers</a> dédié à la création d’un ensemble de Widgets thémables adoptant Material Design.</p>
<p><img alt="Image d’exemple de KivyMD issue de la documentation" src="https://img.linuxfr.org/img/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f486561545468656174522f4b6976794d442d646174612f6d61737465722f67616c6c6572792f70726576696f75732e706e67/previous.png" title="Source : https://raw.githubusercontent.com/HeaTTheatR/KivyMD-data/master/gallery/previous.png"/></p>
<p><em>L'image ci-dessus est issue de <a href="https://kivymd.readthedocs.io/en/latest/">la documentation de KivyMD</a>, vous trouverez également des démos vidéo sur le <a href="https://github.com/kivymd/KivyMD">dépôt du projet</a>.</em></p>
<h2 id="toc-quelques-limitations">Quelques limitations</h2>
<p>Une petite note sur mon expérience personnelle (<a href="https://linuxfr.org/users/goffi">Goffi</a>). Kivy est un excellent cadriciel, et l’équipe est accueillante et réactive : c’est un projet que je recommanderais en général. Ceci dit, dans mon cas particulier (un client XMPP ayant de nombreuses fonctionnalités), j’ai quelques limitations qui me poussent actuellement à chercher des alternatives, notamment basées sur Qt (PyQt et PySide) :</p>
<ul>
<li>l’accessibilité est un problème majeur. <a href="https://github.com/kivy/kivy/issues/8596">L’équipe y travaille</a>, mais aujourd’hui les applications Kivy ne sont pas accessibles. C’est notamment dû au fait que l’interface utilisateur est entièrement gérée par Kivy, au lieu d’utiliser des composants natifs, et c’est un point complètement bloquant pour moi.</li>
<li>il n’y a pas de webview ou de rendu HTML natif, ce qui est bloquant parce que je fais du rendu de blogs.</li>
<li>le rendu de texte est incomplet, notamment sur les plateformes mobiles. C’est compliqué de faire un rendu riche avec des émojis, par exemple, un gros problème pour une application de messagerie de nos jours.</li>
<li>le support des portails Freedesktop est inexistant : il faut faire l’implémentation à la main, alors qu’il est natif sur des cadriciels majeurs comme GTK ou Qt. Je pense par exemple à l’ouverture ou l’enregistrement de fichier. Les portails sont particulièrement nécessaires si on veut voir son application sur <a href="https://flatpak.org/">Flatpak</a>. Plus de détails sur <a href="https://github.com/kivy/kivy/issues/7695">ce ticket</a>.</li>
<li>le support Wayland existe, mais lors de mes tests sur des distributions GNU/Linux sur Pinephone, il n’a pas fonctionné et je n’ai pas pu afficher l’application.</li>
<li>le chargement de l’interprète Python prend un certain temps, ce qui rend le lancement de l’application sur plateformes mobiles telle qu’Android et probablement iOS (que je n’ai pas testé) un peu lent. Sachant que sur ces plateformes l’application peut être tuée à n’importe quel moment auquel cas il faut tout relancer, cela peut mener à une mauvaise expérience utilisateur. Ceci dit, avec une distribution optimisée (en enlevant les paquets non utilisés), et sur les téléphones actuels qui sont très puissants, le problème est sans doute moindre.</li>
</ul>
<p>Notez que je n’ai pas eu l’occasion de travailler avec Kivy récemment, peut-être que ces remarques ne sont plus à jour. Merci d’indiquer en commentaires s’il y a eu de l’évolution sur ces points.</p>
<p>Aussi, mon cas d’utilisation est très demandant (rendu HTML, affichage de texte performant, etc). Dans la plupart des cas, Kivy remplit sans problème toutes les cases (sauf l’accessibilité, qui reste son problème le plus important à mon sens).</p>
<h2 id="toc-conclusion">Conclusion</h2>
<p>Comme vous pouvez le voir, un travail considérable a été effectué sur Kivy et son écosystème, et il en sort un cadriciel performant, pratique, et qui peut potentiellement fonctionner sur la plupart des plateformes. Kivy est agréable à utiliser, et dispose d’une communauté très active et disponible.</p>
<p>Ce cadriciel mérite de s’y attarder, et est une option sérieuse si vous voulez développer un projet rapidement pour une ou plusieurs plateformes.</p>
<h2 id="toc-une-note-dhistoire">Une note d’histoire</h2>
<p>Cette dépêche a été commencée le 04 octobre 2018 à 14:19 (au premier jour de la Pycon FR 2018, à Lille, où une partie de l’équipe de Kivy était présente). Je crois que c’est haut la main la dépêche qui est restée le plus longtemps dans l’espace de rédaction. Comme quoi, tout vient à point à qui sait attendre, comme dirait l’autre.</p>
<p>Merci à toutes les personnes qui ont participé à la correction de la dépêche.</p>
</div><div><a href="https://linuxfr.org/news/kivy-un-cadriciel-graphique-unique-en-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/115418/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/kivy-un-cadriciel-graphique-unique-en-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Goffi,vmagnin,BAud,Julien Jorge,orfenor,tisaac,palm123,dovik</name>
        </author>
    </entry>
    <entry>
        <title>PyConFR 2025,  à Lyon du 30 octobre au 2 novembre</title>
        <link href="https://linuxfr.org/news/pyconfr-2025-a-lyon-du-30-octobre-au-2-novembre" />
        <id>https://linuxfr.org/news/pyconfr-2025-a-lyon-du-30-octobre-au-2-novembre</id>
        <updated>2025-05-05T10:42:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>L’Association Francophone Python (AFPy) organise la PyConFR 2025 du jeudi 30 octobre au dimanche 2 novembre. Pour cette 16e édition, nous sommes accueillis par le Campus René Cassin de Lyon !</p>
<p><img alt="Logo de la PyConFR 2025" src="https://img.linuxfr.org/img/68747470733a2f2f7777772e7079636f6e2e66722f323032352f7374617469632f696d616765732f6c6f676f2d66756c6c2e737667/logo-full.svg" title="Source : https://www.pycon.fr/2025/static/images/logo-full.svg"/></p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/115621" hreflang="fr" title="https://www.pycon.fr/2025/fr/">PyConFR 2025</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/115622" hreflang="fr" title="https://cfp.pycon.fr/pyconfr-2025/cfp">Proposer un sujet à la PyConFR 2025</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/115623" hreflang="fr" title="https://www.pycon.fr/2025/fr/support.html">Supporter l’évènement</a></li><li>lien nᵒ 4 : <a href="https://linuxfr.org/redirect/115624" hreflang="fr" title="https://www.afpy.org/">Association Francophone Python (AFPy)</a></li><li>lien nᵒ 5 : <a href="https://linuxfr.org/redirect/115625" hreflang="fr" title="https://www.pycon.fr/2025/fr/conduct.html">Code de conduite de la PyConFR</a></li></ul><div><p>La PyConFR, c’est un évènement gratuit sur 4 jours autour du langage de programmation Python. Elle est composée deux jours de développements participatifs (sprints), puis de deux jours de conférences et ateliers.</p>
<p>L’appel à propositions est ouvert jusqu’au 20 juillet. Peu importe votre niveau en Python, vous pouvez proposer un sujet de sprint, de conférence ou d’atelier ! Venez parler de développement logiciel, de diversité, de communauté, faire un retour d’expérience sur un outil, présenter votre projet, un domaine d’activité…</p>
<p>Comme tous les ans, nous proposons aux personnes habituellement peu représentées en conférence de l’aide pour trouver un sujet, rédiger la proposition de conférence, rédiger le support de conférence et pour répéter. Vous pouvez nous contacter à l’adresse <a href="mailto:diversite@afpy.org">diversite@afpy.org</a> si vous pensez en avoir besoin.</p>
<p>Enfin, la PyConFR est entièrement financée par les sponsors. Si vous connaissez des sponsors potentiels, n’hésitez pas à leur parler de l’évènement !</p>
</div><div><a href="https://linuxfr.org/news/pyconfr-2025-a-lyon-du-30-octobre-au-2-novembre.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139108/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/pyconfr-2025-a-lyon-du-30-octobre-au-2-novembre#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>grewn0uille,Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>Yaal Coop accueille les journées Libre Entreprise 2025</title>
        <link href="https://yaal.coop/blog/yaal-coop-accueille-les-journees-libre-entreprise" />
        <id>https://yaal.coop/blog/yaal-coop-accueille-les-journees-libre-entreprise</id>
        <updated>2025-05-04T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Les 24 et 25 avril 2025 se sont déroulées les journées Libre Entreprises comme chaque année. C'est l'occasion pour le réseau de se retrouver pour un moment convivial et de partage. Cette année, Yaal Coop accueillait pour la première fois l'événement.</p>
<h2>Libre Entreprise, c'est quoi ?</h2>
<p>Le réseau <a href="https://libre-entreprise.org/">Libre entreprise</a> est un groupement d'entreprises qui partagent des valeurs communes fortes : la promotion du logiciel libre, la transparence, l'horizontalité, l'autogestion et une juste répartition de la rémunération.</p>
<p>Initié par 3 entreprises fondatrices, le réseau voit le jour en 2000. Aujourd'hui, <a href="https://libre-entreprise.org/liste-des-entreprises/">12 entreprises</a> libres continuent de faire vivre et évoluer ces valeurs avec autant de conviction qu'il y a 25 ans.</p>
<p><a href="https://libre-entreprise.org/charte/">Notre charte</a> le raconte à sa manière.</p>
<h2>À la découverte du réseau LE</h2>
<p>Entre nous, on parle du réseau LE ou simplement LE que l'on prononce : "elleux".
<em>Un heureux hasard quand on défend aussi l'inclusivité au sein de nos entreprises libres.</em></p>
<p>J'ai intégré <a href="https://yaal.coop/">Yaal Coop</a> il y a quelques mois, en octobre 2024. Ma rencontre du réseau Libre entreprise est une totale découverte, et les journées LE une grande première.</p>
<p>Au delà des personnalités engagées et ouvertes du réseau, j'ai surtout découvert un collectif porteur d'une ambition vieille de 25 ans et qui récolte aujourd'hui quelques lauriers. Le logiciel libre aurait très bien pu finir oublié ou relégué à un système marginal, mais les promoteurs et créateurs ont su, par leur engagement et leur persévérance faire connaître et reconnaître ses valeurs :</p>
<ul>
<li>la liberté d'utiliser le logiciel</li>
<li>la liberté de copier le logiciel</li>
<li>la liberté d'étudier le logiciel</li>
<li>la liberté de modifier le logiciel et de redistribuer les versions modifiées.</li>
</ul>
<p>Derrière ces principes, se dressent des idées plus grandes, plus larges, des valeurs humaines au-delà du logiciel, une vision sociétale qui vise à replacer la coopération des individus au centre et en priorité des rapports de rentabilité, de profit et de propriété.</p>
<h2>Les journées LE</h2>
<p>Organisées en forum ouvert (ou non-convention), plusieurs sujets ont été proposés puis traités sous formes diverses : débats, ateliers, présentation, échanges d'expériences, etc.</p>
<p><strong>Le tout régit par des règles contraignantes:</strong></p>
<ul>
<li>les personnes présentes sont les bonnes personnes,</li>
<li>ça commence quand ça commence,</li>
<li>ça finit quand ça finit,</li>
<li>ce qui se passe est ce qui pouvait arriver de meilleur.</li>
</ul>
<p><strong>Et une loi impérative :</strong>
la loi des deux pieds. Si je ne participe pas et que je n'apprends rien, alors je suis mes deux pieds pour faire autre chose, quoique ce soit. Ainsi, on peut sortir et rejoindre un sujet quand bon nous semble et personne ni ne se vexe, ni ne juge, puisque nous sommes contraints de nous soumettre à cette loi supérieure entre toutes.</p>
<h4>Immersion</h4>
<p>Après un temps de proposition d'ateliers et réservations de salles et créneaux, notre <strong>première journée</strong> pouvait commencer.
Un suivi en direct de tout ce qui est abordé est possible grâce à une prise de note commune. Ainsi, tout en assistant à une présentation, je peux suivre le débat qui a lieu quelques mètres plus loin via le pad.</p>
<p>J'ai d'abord assisté à l'atelier de création d'une matrice des compte-rendus LE. Chaque mois, chaque entreprise libre produit un compte rendu à l'attention du réseau. Ces compte rendus sont l'occasion de générer des échanges et de provoquer des résolutions et conseils au sein du réseau. Il était important de revenir sur ce pilier de notre fonctionnement en proposant une matrice qui recense les sujets attendus par les lecteurs.</p>
<p>Nous avons ensuite enchaîné avec la Communication du réseau. Nous avons réfléchi à comment marquer notre identité et comment communiquer sur le réseau LE et ses membres au sens large. Nous allons tester à petite échelle sur <a href="https://matrix.to/#/#bonjour-libre-entreprise:codelutin.com">notre salon public</a> dans un premier temps. Nos efforts pourraient également aboutir à la création d'un forum LE.</p>
<p>J'ai ensuite suivi les échanges entre plusieurs membres historiques du réseau sur leurs problématiques liées au nombre de salariées, au besoin d'un nouveau souffle, au manque d'implication, etc. Ces échanges sont éloignées des problématiques d'une jeune coopérative comme Yaal Coop, mais il n'en reste que ces flux d'expériences et de diversité sont très enrichissants.</p>
<p>Cette première journée s'est poursuivi autour d'un verre suivi d'un dîner au restaurant. Miam !</p>
<p>Lors de la <strong>deuxième journée</strong>, l'organisation a été plus informelle. Un nouveau sujet était proposée à la volée à la clôture du précédent. S'en suivaient alors des échanges entre les participants jusqu'à clôture du sujet. Nous avons échangé sur les méthodes de communication et les formations afférentes, l'équilibre vie pro/perso, Les finances, la communication interne...</p>
<p>J'ai malheureusement manqué certains ateliers, dont j'ai pu saisir la teneur via les compte-rendus. Ainsi, bien d'autres sujets ont été abordés et débattus : les embauches, la protection du gérant, la gouvernance et la prise de décision, (...), et notre projet commun : le Label RSE Libre Entreprise</p>
<h2>En conclusion</h2>
<p>Cette expérience enrichissante (que je serai ravi de renouveler l'année prochaine) m'aura appris à mieux comprendre et connaître les motivations et les enjeux de notre réseau d'entreprises libres. Nous avons à cœur de nous soutenir et de nous entraider avec l'ambition d'agir sur notre société, de créer une proposition nouvelle. Du moins, être innovants au sein de nos structures, c'est déjà beaucoup. Chaque entité du réseau se questionne sur le rapport au travail, sur la qualité de vie, sur notre impact sociétal. chacune multiplie aussi les tentatives et reste à l'écoute pour toujours améliorer et parfaire nos fonctionnements internes et nos rapports avec nos partenaires et clients.</p>
<p>Le réseau <a href="https://libre-entreprise.org/">Libre entreprise</a> transcende le logiciel libre pour devenir un espace d'entraide et d'engagement afin de promouvoir des modèles plus justes et respectueux de l'humain.</p>
            </div>
        </content>
        <author>
            <name>Sébastien Birolleau &lt;sebastien@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Reverse DNS en masse</title>
        <link href="https://discuss.afpy.org/t/reverse-dns-en-masse/2584" />
        <id>https://discuss.afpy.org/t/reverse-dns-en-masse/2584</id>
        <updated>2025-05-01T20:55:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>J’avais ce projet en tête depuis une petite semaine, bah voilà c’est fait :</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<a href="https://pypi.org/project/in-addr-arpa/" rel="noopener" target="_blank">pypi.org</a>
</header>
<article class="onebox-body">
<h3><a href="https://pypi.org/project/in-addr-arpa/" rel="noopener" target="_blank">Client Challenge</a></h3>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>TL;DR:</p>
<pre><code class="lang-plaintext">$ in-addr.arpa 9.9.9.9/24
9.9.9.9 dns9.quad9.net
9.9.9.10 dns10.quad9.net
9.9.9.11 dns11.quad9.net
9.9.9.12 dns12.quad9.net
</code></pre>
<p>Étape suivante, jouer avec in-addr.arpa dans <a class="inline-onebox" href="https://gitlab.adullact.net/dinum/noms-de-domaine-organismes-secteur-public">DINUM / noms-de-domaine-organismes-secteur-public · GitLab</a></p>
<p><small>2 messages - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/reverse-dns-en-masse/2584">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114421230994437550" />
        <id>https://mamot.fr/@AFPy/114421230994437550</id>
        <updated>2025-04-29T13:23:48Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                PyConFR 2025 from October 30 to November 2, 2025<br />Call for proposals open until July 20, 2025 inclusive
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114421226418202607" />
        <id>https://mamot.fr/@AFPy/114421226418202607</id>
        <updated>2025-04-29T13:22:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                PyConFR 2025 se déroulant du 30 octobre au 2 novembre 2025<br />Call for proposals ouvert  jusqu'au 20 juillet 2025 inclus
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Traductions en Python vs. accessibilité = meh</title>
        <link href="https://discuss.afpy.org/t/traductions-en-python-vs-accessibilite-meh/2580" />
        <id>https://discuss.afpy.org/t/traductions-en-python-vs-accessibilite-meh/2580</id>
        <updated>2025-04-28T12:08:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello !</p>
<p>L’ami <a class="mention" href="https://discuss.afpy.org/u/thibaudcolas">@thibaudcolas</a> s’est décidé à poster ce sujet-là sur le discuss de Python <a class="inline-onebox" href="https://discuss.python.org/t/accessibility-of-multilingual-content-with-mixed-translation/89902/3" rel="noopener nofollow ugc">Accessibility of multilingual content with mixed translation - #3 by sirosen - Ideas - Discussions on Python.org</a> en supposant avec raison que ça aiderait mieux de le poster là-bas que sur mon épaule (même si j’ai accueilli avec grand sérieux le sujet sur mon épaule).</p>
<p>Le symptôme principal c’est qu’il y a des soucis d’accessibilité quand on a une page web avec du contenu partiellement traduit (la synthèse vocale de texte en anglais avec un lecteur réglé sur français par ex. c’est la lose).</p>
<p>Idéalement quand on a une page en français, traduite depuis l’anglais, il faudrait que l’élément html porte <code>lang="fr"</code>, et que chaque chaîne non traduite soit enrobée dans un élément portant <code>lang="en"</code>. Mais comment qu’on peut faire techniquement ?</p>
<p>Je voulais te pointer ce sujet <a class="mention" href="https://discuss.afpy.org/u/mdk">@mdk</a> vu que tu es ma référence pour tout le Python un peu pointu, et notamment pour les traductions.</p>
<p><small>9 messages - 6 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/traductions-en-python-vs-accessibilite-meh/2580">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>tut-tuuut</name>
        </author>
    </entry>
    <entry>
        <title>Un agenda culturel participatif</title>
        <link href="https://linuxfr.org/users/trivial/journaux/un-agenda-culturel-participatif" />
        <id>https://linuxfr.org/users/trivial/journaux/un-agenda-culturel-participatif</id>
        <updated>2025-04-27T19:04:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Il y a 2 ans maintenant, avec une amie on faisait le constat qu'il n'existait pas d'agenda culturel pour Clermont-Ferrand et ses environs. </p>
<p>Après un petit tour d’horizon des outils disponibles (en particulier un import quotidien de sources hétérogènes), et n’ayant rien identifié qui corresponde à notre cahier des charges, j’ai commencé en septembre 2023 à coder un logiciel en m’appuyant sur django, et plein d’autres briques libres. Au fil des mois, c’est devenu relativement fonctionnel, et en septembre 2024, on a commencé à annoncer autour de nous <a href="https://pommesdelune.fr/">https://pommesdelune.fr/</a>.</p>
<p><img alt="Capture d'écran de pommes de lune" src="https://img.linuxfr.org/img/68747470733a2f2f626c6f672e6a6d7472697669616c2e696e666f2f77702d636f6e74656e742f75706c6f6164732f323032352f30342f696d6167652d31303234783538362e706e67/image-1024x586.png" title="Source : https://blog.jmtrivial.info/wp-content/uploads/2025/04/image-1024x586.png"/></p>
<p>Au fil des premiers mois, plusieurs personnes sont venues nous rejoindre, pour participer au développement, à la modération, à la diffusion ou encore à la prospection/curation, afin que l’agenda soit de plus en plus complet.</p>
<h2 id="toc-fonctionnement-de-lagenda-culturel">Fonctionnement de l'agenda culturel</h2>
<p>La particularité fonctionnelle de l’outil, c’est qu’il permet l’import automatique d’un grand nombre de sources, facilitant le travail quotidien des personnes qui font vivre l’agenda. On s’est focalisés sur le Puy-de-Dôme, et on essaye de couvrir toutes les activités culturelles, bien au delà des simples concerts de musique actuelle. C’est aujourd’hui plus de 170 sources qui sont intégrées chaque nuit.</p>
<p>L’outil permet également aux internautes de soumettre un événement ponctuel, qui sera bien sûr intégré après modération. On s’appuie sur un ensemble d’étiquettes et de catégories pour classer les événements, qui sont aussi géolocalisés. L’interface permet de filtrer et de rechercher de manière fine, afin de trouver son bonheur. Elle permet aussi de générer un flux ical correspondant au filtrage choisi, afin d’alimenter son propre agenda.</p>
<p>La pile logicielle s’appuie sur <a href="https://www.djangoproject.com/">django</a>, <a href="https://redis.io/">redis</a>, <a href="https://docs.celeryq.dev/en/stable/">celery</a>, <a href="https://www.selenium.dev/">selenium</a>, <a href="https://feathericons.com/">feather icons</a>, ou encore <a href="https://picocss.com/">Pico CSS</a>. Le tout est <a href="https://forge.chapril.org/jmtrivial/agenda_culturel/">distribué</a> sous licence AGPL.</p>
<p>Depuis la publication, je continue régulièrement à améliorer l’outil, pour qu’il corresponde de plus en plus aux idées que l’équipe qui anime pommes de lune. À vrai dire, j’ai du mal à m’arrêter :</p>
<p><img alt="calendier d'activité sur la forge chapril" src="https://img.linuxfr.org/img/68747470733a2f2f626c6f672e6a6d7472697669616c2e696e666f2f77702d636f6e74656e742f75706c6f6164732f323032352f30342f696d6167652d312e706e67/image-1.png" title="Source : https://blog.jmtrivial.info/wp-content/uploads/2025/04/image-1.png"/></p>
<p>Les défis sont nombreux : </p>
<ul>
<li>récupérer les informations depuis des sites internet qui parfois font tout pour interdire les robots d’explorer leur contenu (facebook, helloasso, etc),</li>
<li>intégrer des sources très variées, car chaque organisme du territoire a ses propres modes de diffusion,</li>
<li>réussir à extraire et structurer une donnée à partir d’informations prévues la plupart du temps pour être lues par des humains, et pas par des machines,</li>
<li>gérer les mises à jour des événements depuis les sources, l’édition locale, la détection de doublons, la géolocalisation des événements,</li>
<li>fournir une interface de consultation ergonomique, agréable, rapide et fonctionnelle,</li>
<li>fournir une interface de modération efficace, pour économiser un maximum de temps aux modérateurices.</li>
</ul>
<p>En plus du projet principal d’agenda culturel, j’ai aussi récemment développé une petite bibliothèque indépendante pour extraire les dates et heures présentes dans un texte sous forme libre : <a href="https://forge.chapril.org/jmtrivial/chronostring">chronostring</a>. Cette bibliothèque fonctionne par détection de motifs élémentaires, puis par la consolidation des informations présentes, jusqu’à arriver à une description complètement structurée des dates et heures.</p>
<h2 id="toc-voir-aussi"> Voir aussi</h2>
<ul>
<li><a href="https://blog.jmtrivial.info/2025/04/27/un-agenda-culturel-participatif/">l'article sur mon blog</a></li>
<li><a href="https://forge.chapril.org/jmtrivial/agenda_culturel/">le code source de l'agenda</a></li>
<li><a href="https://pommesdelune.fr">l'agenda pommes de lune</a></li>
</ul>
<div><a href="https://linuxfr.org/users/trivial/journaux/un-agenda-culturel-participatif.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/139007/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/trivial/journaux/un-agenda-culturel-participatif#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>jm trivial</name>
        </author>
    </entry>
    <entry>
        <title>Gestion simple de tournois sportif PyTournois</title>
        <link href="https://linuxfr.org/news/gestion-simple-de-tournois-sportif-pytournois" />
        <id>https://linuxfr.org/news/gestion-simple-de-tournois-sportif-pytournois</id>
        <updated>2025-04-25T08:28:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Sportifs du dimanche, on a souvent besoin de gérer des tournois très simples du type « tout le monde rencontre tout le monde » avec quelques contraintes:</p>
<ul>
<li>nombre de terrains limité ;</li>
<li>temps d’attente minimal entre deux matchs ;</li>
<li>règles variées sur la gestion des scores.</li>
</ul>
<p>Depuis une vingtaine d’années, je développe différents sites en Python/Django. Du coup j’ai fabriqué un début de site :).</p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/115513" hreflang="fr" title="https://framagit.org/bonnegent/pytournois">Code de PyTournois</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/115514" hreflang="fr" title="https://tournois.bonnegent.fr/static/docs/">Documentation</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/115515" hreflang="fr" title="https://tournois.bonnegent.fr/">Démonstration</a></li></ul><div><h3 id="toc-code">Code</h3>
<p>Libriste depuis toujours, le code du projet est sous licence GPL. Actuellement très simple, le site permet de gérer uniquement le mode « toutes les équipes se rencontrent ». Plus tard, suivant les retours, les utilisations et mon temps libre, j’ajouterai d’autres modes (par exemple pour gérer des groupes de placements).</p>
<p>Pour éviter les calculs inutiles, l’affectation des rencontres utilise des grilles de placement. Ces grilles sont calculées une fois pour toutes et contenues dans le projet. L’avantage est d’être efficace et rapide sur la génération de toutes les rencontres. L’inconvénient est que seules quelques combinaisons sont actuellement disponibles :)</p>
<h3 id="toc-fonctionnement">Fonctionnement</h3>
<p>Le fonctionnement est très simple, le principe de base est que toutes les informations sont visibles sans connexion. Il y a quatre grands rôles utilisateurs:</p>
<ul>
<li>administrateur: sert surtout pour créer des comptes utilisateurs ;</li>
<li>organisateur: peut créer des équipes et réinitialiser un tournoi ;</li>
<li>arbitre: peut enregistrer/modifier les résultats des matchs ;</li>
<li>anonyme: accès à la liste des matchs et au classement.</li>
</ul>
<p>Les règles de classement sont affichées. On peut également définir un message d’accueil. Si on veut sauvegarder les résultats d’un tournoi, il y a un export au format CSV.</p>
<h3 id="toc-démonstration">Démonstration</h3>
<p>Il y a évidemment un site de démonstration du projet. Le lien se trouve ci-dessous. Les ressources nécessaires pour faire tourner le site sont extrêmement limitées. Si les fonctionnalités du site vous conviennent et que vous voulez l’utiliser pour un club/tournois, n’hésitez pas à me contacter. Je pourrais mettre en ligne une version dédiée gratuitement.</p>
</div><div><a href="https://linuxfr.org/news/gestion-simple-de-tournois-sportif-pytournois.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138934/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/gestion-simple-de-tournois-sportif-pytournois#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Sébastien Bonnegent,Benoît Sibaud,Xavier Teyssier,palm123</name>
        </author>
    </entry>
    <entry>
        <title>Règles d’utilisation des espaces d’échanges de l’AFPy</title>
        <link href="https://discuss.afpy.org/t/regles-d-utilisation-des-espaces-d-echanges-de-l-afpy/2577" />
        <id>https://discuss.afpy.org/t/regles-d-utilisation-des-espaces-d-echanges-de-l-afpy/2577</id>
        <updated>2025-04-25T08:25:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Les règles et buts d’utilisation des espaces d’échanges de l’AFPy ne sont pas forcément clairs pour tout le monde.<br/>
Nous (le Comité Directeur) souhaitons les expliciter afin que toutes les personnes utilisant ou rejoignant ces espaces soient informées.</p>
<p>Les espaces d’échanges permettent à l’association de soutenir son but, à savoir « la vulgarisation auprès d’un public francophone du langage de programmation python et de ses applications ».<br/>
Ces espaces ont pour but de discuter, d’aider et de demander de l’aide sur des sujets autour de Python.</p>
<ol>
<li>les espaces d’échanges sont soumis à la <a href="https://www.afpy.org/docs/charte">Charte</a> de l’association.</li>
<li>la formation et la promotion commerciale ne sont pas autorisées.</li>
<li>le flood n’est pas autorisé. Pour les plateformes le permettant, nous vous invitons à créer des fils de discussion.</li>
</ol>
<p>Si vous souhaitez définir des règles allant à l’encontre du but des espaces d’échanges et de l’AFPy, ou des règles définies ici, nous vous invitons à utiliser des espaces indépendants de l’AFPy.</p>
<p>En cas de non-respect des règles, les membres du Comité Directeur pourront prendre les mesures qu’iels jugent appropriées, allant de l’avertissement à l’exclusion temporaire ou définitive des espaces.</p>
<p>En cas d’incident, que vous soyez victime ou témoin, vous pouvez contacter le Comité Directeur ou un·e de ses membres.<br/>
La liste des membres du Comité Directeur est disponible sur le <a href="https://www.afpy.org/docs/a-propos">site de l’association</a>.</p>
<p><small>2 messages - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/regles-d-utilisation-des-espaces-d-echanges-de-l-afpy/2577">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>14 fonctionnalités Python avancées</title>
        <link href="https://blog.edward-li.com/tech/advanced-python-features/" />
        <id>https://blog.edward-li.com/tech/advanced-python-features/</id>
        <updated>2025-04-23T12:50:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Après 12 ans d’expérience en Python, un·e développeur·se partage des astuces avancées et méconnues, allant bien au-delà des fonctionnalités habituellement présentées comme les générateurs ou les tuples. Un article qui promet d’explorer les aspects les plus sophistiqués et parfois ‘non-pythoniques’ de ce langage populaire, permettant aux développeur·se·s de pousser Python dans ses retranchements.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/33493-14-fonctionnalites-python-avancees#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/33493-14-fonctionnalites-python-avancees">14 fonctionnalités Python avancées</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Comment déployer une app Python en production ?</title>
        <link href="https://ashishb.net/programming/python-in-production-2/" />
        <id>https://ashishb.net/programming/python-in-production-2/</id>
        <updated>2025-04-23T11:48:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez les outils essentiels et les bonnes pratiques pour déployer efficacement vos applications Python en production, avec un focus particulier sur l’analyse de données et le machine learning. Un guide pratique pour les développeur·se·s souhaitant maîtriser le déploiement d’applications Python robustes et performantes en environnement de production.</p>
<a href="https://news.humancoders.com/t/python/items/33490-comment-deployer-une-app-python-en-production"><img src="https://ashishb.net/programming/python-in-production/python-logo.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/33490-comment-deployer-une-app-python-en-production#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/33490-comment-deployer-une-app-python-en-production">Comment déployer une app Python en production ?</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Mission Freelance : Python / Django Rest Framework Paris</title>
        <link href="https://discuss.afpy.org/t/mission-freelance-python-django-rest-framework-paris/2574" />
        <id>https://discuss.afpy.org/t/mission-freelance-python-django-rest-framework-paris/2574</id>
        <updated>2025-04-22T15:42:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>– Développeur Backend Senior – Python / Django REST<br/>
<img alt=":round_pushpin:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/round_pushpin.png?v=14" title=":round_pushpin:" width="20"/> Localisation : 2 jours / semaine sur site (1 jour Pantin 1 jours à Puteaux)<br/>
<img alt=":date:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/date.png?v=14" title=":date:" width="20"/> Démarrage : ASAP<br/>
<img alt=":hourglass_not_done:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/hourglass_not_done.png?v=14" title=":hourglass_not_done:" width="20"/> Durée : 3 mois renouvelable<br/>
TJM : 430€</p>
<p>Hello à tous ! <img alt=":waving_hand:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/waving_hand.png?v=14" title=":waving_hand:" width="20"/></p>
<p>Je suis à la recherche d’un(e) Développeur·se Backend expérimenté·e pour rejoindre un projet technique très stimulant autour de la diffusion de données encodées par satellite <img alt=":satellite:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/satellite.png?v=14" title=":satellite:" width="20"/></p>
<p><img alt=":bullseye:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/bullseye.png?v=14" title=":bullseye:" width="20"/> Le contexte :</p>
<p>Développement d’une API métier au cœur d’un système de communication innovant. L’objectif : générer des messages encodés destinés à des décodeurs, dans un environnement en constante évolution.</p>
<p><img alt=":man_technologist:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/man_technologist.png?v=14" title=":man_technologist:" width="20"/> Ce que tu feras :</p>
<ul>
<li>Conception &amp; développement d’API performantes</li>
<li>Revue de code, TDD, bonnes pratiques</li>
<li>Contribution aux choix d’architecture logicielle</li>
<li>Collaboration étroite avec des ingénieurs backend &amp; cloud</li>
</ul>
<p><img alt=":hammer_and_wrench:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/hammer_and_wrench.png?v=14" title=":hammer_and_wrench:" width="20"/> Stack technique :</p>
<p>Python – Django REST – PostgreSQL – AWS (S3, Lambda) – Docker</p>
<p><img alt=":light_bulb:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/light_bulb.png?v=14" title=":light_bulb:" width="20"/> Ce qu’on recherche :</p>
<ul>
<li>Solide expérience en Django/DRF</li>
<li>À l’aise avec les environnements cloud &amp; conteneurisés</li>
<li>Rigueur, autonomie, bon esprit d’équipe</li>
</ul>
<p>Envie de rejoindre un projet à impact, dans un environnement collaboratif</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/mission-freelance-python-django-rest-framework-paris/2574">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Malik</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris - Meetup Django le 22 avril</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-22-avril/2570" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-django-le-22-avril/2570</id>
        <updated>2025-04-20T11:34:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à toutes et à tous,</p>
<p>Meetup Django le <strong>22 avril 2025</strong> dans les locaux d’ <strong>Octopus Energy/Kraken Tech</strong> 87 Rue de Richelieu, 75002, <strong>Paris</strong>.</p>
<p>L’occasion de se retrouver et d’en apprendre plus sur:</p>
<p><strong>1337 h4ck3r - hacker topics <img alt=":pirate_flag:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/pirate_flag.png?v=14" title=":pirate_flag:" width="20"/>:</strong><br/>
<strong>- crudlfap</strong>, YourLabs - James Pic (Français)<br/>
<strong>- djwebdapp</strong>, PyratzLabs - Thomas Binetruy (Français)</p>
<p>Tres bonne journée à toute/s !</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-22-avril/2570/1">Django Paris Meetup - Avril</a></p>
<p>2025-04-22 19:00 (Europe/Paris) → 2025-04-22 22:00 (Europe/Paris)</p>
</div>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-django-le-22-avril/2570">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>sabderemane</name>
        </author>
    </entry>
    <entry>
        <title>Les outils du logiciel libre pour l&#39;ingénieur</title>
        <link href="https://linuxfr.org/users/toremilac/journaux/les-outils-du-logiciel-libre-pour-l-ingenieur" />
        <id>https://linuxfr.org/users/toremilac/journaux/les-outils-du-logiciel-libre-pour-l-ingenieur</id>
        <updated>2025-04-20T10:33:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, </p>
<p>A la rentrée, je relance un cours sur les outils du logiciel libre pour l'ingénieur. L'idée est de familiariser les étudiants au monde du logiciel libre, qu'ils ne connaissent que trop rarement. </p>
<p>Le "cours" est en fait essentiellement construit autour de deux gros TPs dans lesquels les étudiants vont apprendre à combiner plusieurs commandes pour :</p>
<ol>
<li>construire une vidéo des températures sur le territoire américain à partir des fichiers texte de ces mesures,</li>
<li>Construire une vidéo d'une éruption solaire à partir des images capturées par
le <a href="https://sdo.gsfc.nasa.gov/"><em>Solar Dynamics Observatory</em></a>
</li>
</ol>
<p><img alt="Image du soleil, en fausse couleur, à partir des données du SDO" src="https://img.linuxfr.org/img/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6a6572656d796669782f6c696e757866722f6d61737465722f323032352d30342d32302f736f6c65696c2e706e67/soleil.png" title="Source : https://raw.githubusercontent.com/jeremyfix/linuxfr/master/2025-04-20/soleil.png"/></p>
<p><img alt="Températures sur le territoire américain, à partir des données du NOAA" src="https://img.linuxfr.org/img/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f6a6572656d796669782f6c696e757866722f6d61737465722f323032352d30342d32302f6d6574656f2e706e67/meteo.png" title="Source : https://raw.githubusercontent.com/jeremyfix/linuxfr/master/2025-04-20/meteo.png"/></p>
<p>Les données pour les températures sur le territoire américan étaient mises à disposition par le <a href="https://www.noaa.gov/"><em>National Oceanic and Atmospheric Agency (NOAA)</em></a> que <a href="https://www.science.org/content/article/trump-seeks-end-climate-research-premier-u-s-climate-agency">l'administration Trump est entrain de saccager</a>. Heureusement que de courageux volontaires, comme le <a href="https://climatemirror.org/">Climate Mirror</a>, tentent de préserver ces données !</p>
<p>Pour en revenir aux sujets de TP, quelques commandes que les étudiants sont amenés à utiliser :</p>
<ul>
<li>lynx: pour interroger un site et récupérer la liste des images depuis le site
du SDO,</li>
<li>zenity: pour proposer une petite interface utilisateur,</li>
<li>convert: pour redimensionner les images, les colorer, y incruster du texte,</li>
<li>awk, sed, grep, join : pour filtrer les URLs, remanier les noms de fichiers,
extraire les dates de prise de vue des noms de fichier,</li>
<li>python, basemap : pour le tracé des données avec un fond de carte,</li>
<li>ffmpeg: pour construire une vidéo.</li>
</ul>
<p>C'est un cours que je donnai il y a quelques années, avec un support PDF que j'ai préféré convertir en un site web mkdocs. </p>
<p>Le support en ligne est disponible à l'adresse <a href="https://jeremyfix.github.io/OutilsLibres/">https://jeremyfix.github.io/OutilsLibres/</a> avec les sujets de TP et également un petit annuaire d'outils par thèmes : </p>
<ul>
<li>interaction avec une machine distante : ssh, scp, rsync, multiplexeurs de terminaux,</li>
<li>automatisation de tâches : makefile,</li>
<li>filtrage de documents : awk, sed,</li>
<li>manipulation d'images : imagemagick, gimp,</li>
</ul>
<p>Je ne suis absolument pas dans l'idée d'être exhaustif ni de remplacer d'autres ressources comme <a href="https://en.wikibooks.org/wiki/Guide_to_Unix">wikibooks</a>, <a href="https://www.gnu.org/manual/manual.html">la documentation GNU</a>, etc.</p>
<p>N'hésites pas à me dire ce que tu en penses.</p>
<div><a href="https://linuxfr.org/users/toremilac/journaux/les-outils-du-logiciel-libre-pour-l-ingenieur.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138952/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/toremilac/journaux/les-outils-du-logiciel-libre-pour-l-ingenieur#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>toremilaC</name>
        </author>
    </entry>
    <entry>
        <title>yahi un parseur de logs pour remplacer awstats</title>
        <link href="https://discuss.afpy.org/t/yahi-un-parseur-de-logs-pour-remplacer-awstats/2569" />
        <id>https://discuss.afpy.org/t/yahi-un-parseur-de-logs-pour-remplacer-awstats/2569</id>
        <updated>2025-04-19T08:49:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://pypi.org/project/yahi/" rel="noopener nofollow ugc">Yahi</a> est un module python deux en un.</p>
<p>Il contient un agrégateur de statistique basé sur les regexps. Pour l’instant seules sont fournies les regexps de format Common log format pour les serveurs web courants (nginx, apache) et lighthttpd et varnish, mais il est aisé de par exemple l’utiliser pour analyser les journaux auth.log.</p>
<p>Il contient ensuite un générateur de visualisation « tout en une page html » dont la <a href="https://jul.github.io/cv/demo.html?route=geo" rel="noopener nofollow ugc">démonstration est ici</a> qui à l’avantage d’embarquer en une page : les données, la CSS, les visualisations, et d’être « bookmarkable » grâce à quelques ruses de javascript, ce qui rend son hébergement aisé pour les sysadmins.</p>
<p>Son API permet en outre de faire des agrégations plus compliquées.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/yahi-un-parseur-de-logs-pour-remplacer-awstats/2569">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>jul</name>
        </author>
    </entry>
    <entry>
        <title>Chef-Cheffe technique et fonctionnel d&#39;applications métier web - Toulouse - CDI</title>
        <link href="https://discuss.afpy.org/t/chef-cheffe-technique-et-fonctionnel-dapplications-metier-web-toulouse-cdi/2567" />
        <id>https://discuss.afpy.org/t/chef-cheffe-technique-et-fonctionnel-dapplications-metier-web-toulouse-cdi/2567</id>
        <updated>2025-04-18T13:28:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><strong><a href="https://makina-corpus.com/" rel="noopener nofollow ugc">Makina Corpus</a></strong> <strong>développe des projets web ou mobiles d’envergure</strong> combinant notamment la cartographie, l’intelligence artificielle, le traitement et l’analyse de données, la dataviz. Nos applications phares sont au service de domaines tels que la randonnée et la gestion d’espaces naturels (Geotrek), l’aménagement et le développement économique de territoires (Actif), <a href="https://makina-corpus.com/application-web-mobile/regard-altitude-outil-open-source-comprendre-agir-changement-climatique#corps" rel="noopener nofollow ugc">la prévention des risques naturels</a>, <a href="https://makina-corpus.com/gestion-de-leau/refonte-accueil-hydroportail-schapi#corps" rel="noopener nofollow ugc">la gestion de l’eau</a>…</p>
<p><strong>Notre organisation et nos prestations se construisent sur trois piliers</strong> : les logiciels libres, le respect de l’humain et l’engagement en faveur de l’environnement; trois valeurs fondamentales que nous développons et renforçons grâce à notre charte RSE.</p>
<p><em>Découvrez quelques uns de nos projets : <a class="inline-onebox" href="https://makina-corpus.com/references" rel="noopener nofollow ugc">Références | Makina Corpus</a>, et retrouvez-nous sur Welcome To The Jungle (<a class="inline-onebox" href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Makina Corpus : photos, vidéos, recrutement</a>).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-10370-la-mission-1" name="p-10370-la-mission-1"></a>La mission</h2>
<p><strong>Vous intégrerez un pôle interdisciplinaire (chefs de projets, ergonomes, graphistes, développeurs Back/Front/Mobile, SIG, DBA…) réparti entre Toulouse, Nantes et Paris, au sein duquel vous aurez pour mission de piloter les projets de nos clients et de participer de façon active au développement commercial.</strong></p>
<p><strong><strong>Vos missions consisteront à :</strong></strong></p>
<ul>
<li>Identifier et mettre en œuvre au sein du projet les <strong>besoins technico-fonctionnels</strong> des clients</li>
<li>Formaliser, organiser, planifier et contrôler les phases de réalisation</li>
<li><strong>Piloter et coordonner</strong> l’équipe projet</li>
<li>Assurer le suivi du planning et le contrôle de la qualité<strong>Notre organisation et nos prestations se construisent sur trois piliers</strong> : les logiciels libres, le respect de l’humain et l’engagement en faveur de l’environnement; trois valeurs fondamentales que nous développons et renforçons grâce à notre charte RSE.</li>
<li>Gérer les <strong>engagements vis-à-vis du client</strong> et s’assurer de sa satisfaction</li>
<li><strong>Fidéliser</strong>, entretenir et développer le portefeuille client existant</li>
<li><strong>Participer aux phases d’avant-vente en relation avec le client et avec nos équipes, rédiger une proposition commerciale</strong></li>
</ul>
<p><em>Nous mettrons en place un plan de formation</em> <em>et un accompagnement par plusieurs chefs de projets</em> <em>adapté pour vous permettre d’acquérir rapidement une très bonne connaissance de l’entreprise, son activité et son environnement, et de vous approprier et maîtriser le</em> <strong>s techniques de gestion de projet web exigeants.</strong></p>
<p><em>Ce poste est ouvert au télétravail partiel (jusqu’à 3 jours/semaine).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-10370-profil-2" name="p-10370-profil-2"></a>Profil</h2>
<p><em>Vous maîtrisez les méthodes et outils de gestion de projets web complexes et techniques, et</em> <em><strong>possédez</strong></em> <em><strong>une expérience de minimum 2 ans sur ce type de poste.</strong></em></p>
<p><em>Vous possédez un</em> <em><strong>background technique dans le développement web.</strong></em></p>
<p><em>Vous avez une appétence commerciale et idéalement une expérience dans la réponse à appels d’offres.</em></p>
<ul>
<li>Vous aimez comprendre les besoins du client, s’approprier son métier et lui proposer des solutions ad<strong>aptées ;</strong></li>
<li>Votre goût du travail en équipe, votre curiosité, vos excellentes qualités relationnelles seront des atouts indispensables. Apprendre toujours plus vous stimule !</li>
</ul>
<p><em>Nous ne précisons pas de diplôme ou de niveau d’études minimum</em> <em>car nous attachons avant tout de l’importance aux compétences et à la passion du métier.</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-10370-informations-complmentaires-3" name="p-10370-informations-complmentaires-3"></a>Informations complémentaires</h2>
<p>Dans la ruche collaborative Makina Corpus, <strong>on dit ce qu’on fait</strong> : les makiniens évoluent dans une ambiance motivante et stimulante (projets et contrib opensource, participations encouragées à des évènements/meetup, émulation entre experts passionnés, technos innovantes à tester, veille…) et contribuent aux valeurs humaines ancrées dans l’ADN de l’entreprise (environnement, équilibre vie pro/vie privée, collaboratif, télétravail…).</p>
<p>Mais surtout chez Makina <strong>on fait ce qu’on dit</strong> : vous avez besoin de le voir pour le croire ? Venez nous rencontrer, un.e makinien.ne pourra vous en parler ! Nos équipes sont mixtes, femmes et hommes du numérique nous vous attendons.</p>
<p><strong>Écrivez-nous et racontez qui vous êtes et ce qui vous anime</strong>. Expliquez-nous en quoi vos motivations et vos compétences sont en adéquation avec nos valeurs et nos activités.</p>
<p><strong>En savoir plus sur notre processus de recrutement :</strong></p>
<p><strong>Nous répondons à chacune des candidatures de manière personnalisée et dans un délai que nous essayons de rendre le plus raisonnable possible. Si votre candidature est sélectionnée, voici comment cela va se passer pour vous :</strong></p>
<ul>
<li>un 1° échange en visio vous sera proposé par Lise notre RRH afin de faire plus ample connaissance et de déterminer si vous, comme nous, souhaitons aller plus loin ;</li>
<li>il y aura ensuite un 2° entretien avec 2 chefs de projet toulousains : ce sera l’occasion de parler du poste, des missions et des projets ;</li>
<li>enfin, vous serez reçu.e par le responsable de l’agence.</li>
</ul>
<p>La décision finale sera prise collectivement par vos différents interlocuteurs. Tout au long du parcours, vous serez en lien direct avec Lise.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/chef-cheffe-technique-et-fonctionnel-dapplications-metier-web-toulouse-cdi/2567">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>Fan club de Weasyprint</title>
        <link href="https://discuss.afpy.org/t/fan-club-de-weasyprint/2565" />
        <id>https://discuss.afpy.org/t/fan-club-de-weasyprint/2565</id>
        <updated>2025-04-17T09:39:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bon, c’est un peu le projet chouchou ici, je propose de parler ici de sa popularité <img alt=":smiling_face_with_sunglasses:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiling_face_with_sunglasses.png?v=14" title=":smiling_face_with_sunglasses:" width="20"/></p>
<p>J’ai découvert <a href="https://github.com/plenaerts/eml2pdf" rel="noopener nofollow ugc"><code>eml2pdf</code></a>, pour convertir des fichier EML en PDF, et <code>weasyprint</code> fait partie des dépendances. <img alt=":ok_hand:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/ok_hand.png?v=14" title=":ok_hand:" width="20"/></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/fan-club-de-weasyprint/2565">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>freezed</name>
        </author>
    </entry>
    <entry>
        <title>videos pyconfr 2024</title>
        <link href="https://discuss.afpy.org/t/videos-pyconfr-2024/2564" />
        <id>https://discuss.afpy.org/t/videos-pyconfr-2024/2564</id>
        <updated>2025-04-16T09:46:22Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous. Pas pu assister à pyconfr 2024. Pas grave, me suis-je dit, les conf vont être captées et publiées. Qqn sait si ça a été capté, et publié?<br/>
J’ai trouvé <a class="inline-onebox" href="https://pyvideo.org/events/pycon-fr-2023.html" rel="noopener nofollow ugc">PyVideo.org · PyCon FR 2023</a>, mais rien pour 2024.</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/videos-pyconfr-2024/2564">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>pierre.imbaud</name>
        </author>
    </entry>
    <entry>
        <title>Une augmentation à l&#39;import des librairies python</title>
        <link href="https://linuxfr.org/users/quiwy/liens/une-augmentation-a-l-import-des-librairies-python" />
        <id>https://linuxfr.org/users/quiwy/liens/une-augmentation-a-l-import-des-librairies-python</id>
        <updated>2025-04-16T00:38:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://pypi.org/project/tariff/">https://pypi.org/project/tariff/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138909/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/quiwy/liens/une-augmentation-a-l-import-des-librairies-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Quiwy</name>
        </author>
    </entry>
    <entry>
        <title>Noms de dépots malveillants inspirés par des LLM</title>
        <link href="https://discuss.afpy.org/t/noms-de-depots-malveillants-inspires-par-des-llm/2563" />
        <id>https://discuss.afpy.org/t/noms-de-depots-malveillants-inspires-par-des-llm/2563</id>
        <updated>2025-04-15T14:01:33Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>ça ferait un bon addendum à la conf “pip install malware”.<br/>
Des attaquant créent des dépôts malveillants avec des noms de packages inventés par des LLM générant du code:</p>
<p><a class="onebox" href="https://arxiv.org/pdf/2406.10279" rel="noopener nofollow ugc" target="_blank">https://arxiv.org/pdf/2406.10279</a></p>
<p>Herdawyn</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/noms-de-depots-malveillants-inspires-par-des-llm/2563">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Herdawyn</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 24 avril</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-24-avril/2562" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-24-avril/2562</id>
        <updated>2025-04-14T12:49:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Boujour tout le monde,</p>
<p>Prochain meetup Python sur Lyon : jeudi 24 avril ! Andrei présentera sa trousse à outils en tant que DevOps.</p>
<p>Rendez-vous à 19h dans les locaux de GenyMobile (métro Saxe-Gambetta) !</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-24-avril/2562/1">La trousse d'outils d'un DevOps</a></p>
<p>2025-04-24 19:00 (Europe/Paris) → 2025-04-24 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-24-avril/2562">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>La PyConFR 2025 !</title>
        <link href="https://discuss.afpy.org/t/la-pyconfr-2025/2560" />
        <id>https://discuss.afpy.org/t/la-pyconfr-2025/2560</id>
        <updated>2025-04-13T18:21:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>Nous sommes ravi·es de vous annoncer que la <a href="https://www.pycon.fr/2025/">PyConFR 2025</a> aura lieu du 30 octobre au 2 novembre à… Lyon <img alt=":tada:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/tada.png?v=14" title=":tada:" width="20"/></p>
<p>Nous vous tiendrons au courant des dates d’ouverture du CFP et de la billeterie !</p>
<p>Si votre entreprise est intéressée pour soutenir cette conférence gratuite, ouverte à toutes et tous, autour du langage Python, n’hésitez pas à consulter les <a href="https://www.pycon.fr/2025/fr/support.html">différentes offres de sponsoring disponibles</a> !</p>
<p>Pour ne manquer aucune nouvelle, vous pouvez nous suivre sur nos différents réseaux (<a href="https://mamot.fr/@AFPy">Mastodon</a>, <a href="https://www.linkedin.com/company/afpy">LinkedIn</a>) et participer sur le <a href="https://discuss.afpy.org/">forum</a> ou le <a href="https://www.afpy.org/discord">salon Discord</a> <img alt=":smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smile.png?v=14" title=":smile:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/la-pyconfr-2025/2560/1">PyConFR 2025</a></p>
<p>2025-10-30 10:00 (Europe/Paris) → 2025-11-02 18:00 (Europe/Paris)</p>
</div>
<p><small>6 messages - 4 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/la-pyconfr-2025/2560">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114330553445729556" />
        <id>https://mamot.fr/@AFPy/114330553445729556</id>
        <updated>2025-04-13T13:03:18Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>The pycon.fr website is now updated with the dates of the next edition of <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a> 2025!<br/>It will take place at Campus René Cassin in Lyon, from October 30 to November 2!<br/>Thanks to Anabelle Nicvert for the graphic charter and logo!</p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/114330550997658376" />
        <id>https://mamot.fr/@AFPy/114330550997658376</id>
        <updated>2025-04-13T13:02:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Ecran de capture de la nouvelle charte graphique du site pycon.fr, montrant les dates de l'évènement étant à Lyon au Campus René Cassin
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Les t-string arrivent !</title>
        <link href="https://discuss.afpy.org/t/les-t-string-arrivent/2559" />
        <id>https://discuss.afpy.org/t/les-t-string-arrivent/2559</id>
        <updated>2025-04-10T21:10:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>TL;DR: Ça s’écrit comme les f-string, mais ce n’est pas transformé en chaîne sur place : ça vaut une instance d’une nouvelle classe, <code>Template</code>, qui représente la chaîne.</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="16" src="https://peps.python.org/_static/py.png" width="16"/>
<a href="https://peps.python.org/pep-0750/" rel="noopener" target="_blank">Python Enhancement Proposals (PEPs)</a>
</header>
<article class="onebox-body">
<img class="thumbnail onebox-avatar" height="200" src="https://peps.python.org/_static/og-image.png" width="200"/>
<h3><a href="https://peps.python.org/pep-0750/" rel="noopener" target="_blank">PEP 750 – Template Strings | peps.python.org</a></h3>
<p>This PEP introduces template strings for custom string processing.</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<aside class="onebox discoursetopic">
<header class="source">
<img class="site-icon" height="32" src="https://us1.discourse-cdn.com/flex002/uploads/python1/optimized/1X/9997f0605d56c4bfecd63594f52f42cdafd6b06a_2_32x32.png" width="32"/>
<a href="https://discuss.python.org/t/pep750-template-strings-new-updates/71594/130" rel="noopener" target="_blank" title="05:24PM - 10 April 2025">Discussions on Python.org – 10 Apr 25</a>
</header>
<article class="onebox-body">
<img class="thumbnail onebox-avatar" height="500" src="https://discuss.afpy.org/uploads/default/optimized/1X/f93ff97c4f381b5e8add5a0c163b4ded29f20ed7_2_500x500.png" width="500"/>
<div class="title-wrapper">
<h3><a href="https://discuss.python.org/t/pep750-template-strings-new-updates/71594/130" rel="noopener" target="_blank">PEP750: Template Strings (new updates)</a></h3>
<div class="topic-category">
<span class="badge-wrapper bullet">
<span class="badge-category-bg" style="background-color: #0088CC;"></span>
<span class="badge-category clear-badge">
<span class="category-name">PEPs</span>
</span>
</span>
</div>
</div>
<p>The Steering Council reviewed today PEP 750: Updates requested by the Steering Council by davepeck · Pull Request #4351 · python/peps · GitHub and we are happy with the changes so we are formally approving the PEP. Congratulations yet again! 🙂</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>C’est génial pour gettext, car, sans les t-strings :</p>
<pre><code class="lang-python">name = "John"
_(f"Hello {name}")
</code></pre>
<p>ne pouvait pas marcher, <code>_</code> recevait la chaîne <code>Hello John</code> qui n’est évidemment pas dans le fichier de traductions. C’est triste, mais c’est donc soit f-strings, soit i18n, pas les deux, on en était réduits à :</p>
<pre><code class="lang-python">name = "John"
_("Hello {name}").format(name=name)
</code></pre>
<p>pour les jeunes, et :</p>
<pre><code>_("Hello %(name)s") % {"name": name}
</code></pre>
<p>pour ceux qui ont la barbe bien blanche.</p>
<p>Avec les t-strings j’espère voir bientôt :</p>
<pre><code>_(t"Hello {name}")
</code></pre>
<p><small>6 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/les-t-string-arrivent/2559">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Sur Clermont-Ferrand - Meetup le 22 avril</title>
        <link href="https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-22-avril/2558" />
        <id>https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-22-avril/2558</id>
        <updated>2025-04-10T14:55:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Notre prochain évènement aura lieu à Clermont le 22 avril à 18h30 pour 1h de talk sur “Une barre de recherche dopée à l’IA”</p>
<p>Inscription obligatoire mais gratuite sur <a class="inline-onebox" href="https://www.meetup.com/pyclermont/events/307213430" rel="noopener nofollow ugc">[Tuto] Une barre de recherche dopée à l'IA, Tue, Apr 22, 2025, 6:30 PM | Meetup</a></p>
<p></p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/3/33640d3979f0e549b18919742004dd9b2d380c71.jpeg" title="py.clermont #10"><img alt="py.clermont #10" height="500" src="https://discuss.afpy.org/uploads/default/optimized/2X/3/33640d3979f0e549b18919742004dd9b2d380c71_2_353x500.jpeg" width="353"/></a></div><br/>
Au plaisir de vous voir prochainement<p></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-22-avril/2558/1">Une barre de recherche dopée à l’IA</a></p>
<p>2025-04-22 18:30 (Europe/Paris) → 2025-04-22 19:30 (Europe/Paris)</p>
</div>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-clermont-ferrand-meetup-le-22-avril/2558">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>drigaudie</name>
        </author>
    </entry>
    <entry>
        <title>Blender/UPBGE + Blockly = coding game en 3D</title>
        <link href="https://discuss.afpy.org/t/blender-upbge-blockly-coding-game-en-3d/2557" />
        <id>https://discuss.afpy.org/t/blender-upbge-blockly-coding-game-en-3d/2557</id>
        <updated>2025-04-09T19:23:57Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Pour faire un <strong>coding game en 3D</strong> le combo qui marche pas mal est <strong>Blockly</strong> (éditeur de code avec de blocs, façon scratch ou app inventor) + <strong>Blender/UPBGE</strong>.</p>
<p>Blender/UPBGE étant en Python, Blockly en javascript, on peut passer par un Websocket, c’est au final plutôt simple.</p>
<p>Petite démo.<br/>
</p><div class="video-placeholder-container">
</div><p></p>
<p>Le code est ici : <a class="inline-onebox" href="https://forge.apps.education.fr/blender-edutech/portail-coulissant/jumeau-numerique" rel="noopener nofollow ugc">Blender-EduTech / Portail coulissant / Jumeau numérique · GitLab</a></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/blender-upbge-blockly-coding-game-en-3d/2557">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>phroy</name>
        </author>
    </entry>
    <entry>
        <title>Recherche mission freelance FastApi / Django</title>
        <link href="https://discuss.afpy.org/t/recherche-mission-freelance-fastapi-django/2555" />
        <id>https://discuss.afpy.org/t/recherche-mission-freelance-fastapi-django/2555</id>
        <updated>2025-04-08T14:53:37Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,<br/>
Je suis en recherche d’une mission en <a class="hashtag-cooked" href="https://discuss.afpy.org/c/python/8"><span class="hashtag-icon-placeholder"><svg class="fa d-icon d-icon-square-full svg-icon svg-node" xmlns="http://www.w3.org/2000/svg"><use></use></svg></span><span>Python</span></a> orienté web.<br/>
Je sors d’une expérience dans une banque où j’ai mis en place avec ma squad une architecture micro-service (fastapi, mongo, rabbitmq) avec du full asynchrone sur des problématiques de forte charge<br/>
<img alt=":man_technologist:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/man_technologist.png?v=14" title=":man_technologist:" width="20"/>  17 ans XP (+8 ans python)<br/>
<img alt=":round_pushpin:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/round_pushpin.png?v=14" title=":round_pushpin:" width="20"/>  Clermont Ferrand (Paris / Lyon)<br/>
<img alt=":briefcase:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/briefcase.png?v=14" title=":briefcase:" width="20"/>  2 jours max de TT / sem<br/>
<img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=14" title=":snake:" width="20"/>  python, FastApi/Django/Flask</p>
<p>Je recherche une mission équivalente ou sur un projet nécessitant une mise en place des bonnes pratiques de développement pour améliorer la qualité du code</p>
<p>Merci pour votre soutien</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/recherche-mission-freelance-fastapi-django/2555">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>drigaudie</name>
        </author>
    </entry>
    <entry>
        <title>scrollbar-canvas</title>
        <link href="https://discuss.afpy.org/t/scrollbar-canvas/2553" />
        <id>https://discuss.afpy.org/t/scrollbar-canvas/2553</id>
        <updated>2025-04-03T09:53:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
j’ai un problème de dimension du “curseur” (Thumb) de mes scrollbars.<br/>
elles remplissent la scrollbar et je ne peux qu’utiliser les flèches pour me déplacer H ou V. Voici mon code:</p>
<pre><code class="lang-python">Frame1 = Frame(fen, background='white')
Frame1.place(x=20, y=y5, width=w1, height=h1)
Frame2 = Frame(Frame1, background='white')
Frame2.place(x=5,y=5, width=w1-10,height=h1-10)
cnvs = Canvas(Frame2, bg='white', width=w1-10, height=h1-10)
cnvs.place(x=0,y=0)
scrollable_frame = Frame(cnvs)
scrollable_frame.bind("&lt;Configure&gt;",lambda e: cnvs.configure(scrollregion=cnvs.bbox("all")))
cnvs.create_window((0, 0), window=scrollable_frame, anchor="nw")
scrollbarv = ttk.Scrollbar(Frame2, orient="vertical", command=cnvs.yview)
cnvs.configure(yscrollcommand=scrollbarv.set)
scrollbarv.pack(side="right", fill="y")
scrollbarh = ttk.Scrollbar(Frame2, orient="horizontal", command=cnvs.xview)
cnvs.configure(xscrollcommand=scrollbarh.set)
scrollbarh.pack(side="bottom", fill="x")
p=30
for n in range(1,300):
	cnvs.create_text(50, p, text=str(n)+' '+"Tkinter &amp; azertyuiopqsdfghjklm",fill="black",font="Times 16 bold")
	p=p+30
</code></pre>
<p>J’y arrive avec une ListBox.<br/>
D’où pourrait venir mon erreur ?<br/>
Cordialement</p>
<p><small>7 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/scrollbar-canvas/2553">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Django 5.2</title>
        <link href="https://www.djangoproject.com/weblog/2025/apr/02/django-52-released" />
        <id>https://www.djangoproject.com/weblog/2025/apr/02/django-52-released</id>
        <updated>2025-04-03T00:28:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Django 5.2 est sorti aujourd’hui même. La version 5.1 ne sera plus officiellement supportée, la dernière version sera 5.1.8.</p>
<a href="https://news.humancoders.com/t/python/items/32168-sortie-de-django-5-2"><img src="https://static.djangoproject.com/img/logos/django-logo-negative.1d528e2cb5fb.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/32168-sortie-de-django-5-2#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/32168-sortie-de-django-5-2">Sortie de Django 5.2</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>davidb583</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Jeudi Programmation de l’ALDIL le 3 avril</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-3-avril/2548" />
        <id>https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-3-avril/2548</id>
        <updated>2025-04-01T10:08:52Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>L’ALDIL refait une séance d’initiation sur Python le jeudi 3 avril à 19h à la salle des Rancy (métro Saxe-Gambetta).</p>
<p>Ce coup-ci ça sera autour de Django.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-3-avril/2548/1">Jeudi Programmation</a></p>
<p>2025-04-03 19:00 (Europe/Paris) → 2025-04-03 21:00 (Europe/Paris)</p>
</div>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-jeudi-programmation-de-l-aldil-le-3-avril/2548">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Questions, idées d&#39;améliorations et quelques petits trucs</title>
        <link href="https://discuss.afpy.org/t/questions-idees-dameliorations-et-quelques-petits-trucs/2545" />
        <id>https://discuss.afpy.org/t/questions-idees-dameliorations-et-quelques-petits-trucs/2545</id>
        <updated>2025-03-31T23:28:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour.<br/>
J’ai pas mal regardé ce site et franchement y a des trucs bien mais on peu passer a coté assez facilement…</p>
<ul>
<li>Le site mêt surtout en avant les conférences et autres trucs qui n’interessent pas forcément au départ (une personne qui code vite fait et veut simplement partager n’a pas forcément envis d’aller a une conférence tout de suite <img alt=":smiley:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiley.png?v=14" title=":smiley:" width="20"/> )</li>
<li>Dans la liste des badges il y a “contribution au wiki” mais… Soit y a pas de wiki soit il est pas indiqué</li>
<li>La page d’aceuil du site ne propose pas de lien ou d’infos sur les éventuels sous-sites (dans communauté il y a bien des liens vers le forum par exemple mais pour découvrir qu’il y a un git faut aller sur ce forum)</li>
<li>Avant il y avait <a href="http://wikipython.flibuste.net/" rel="noopener nofollow ugc">http://wikipython.flibuste.net/</a> (et je crois y avoir mis des trucs en python2 y a longtemps) mais il n’existe plus vraiment</li>
<li>manque de tags.sous catégorie pour la catégorie python. Un tag/sous catégorie par bibliothèques/applis serait pas mal pour s’y retrouver (ex wxpython, blender, gimp, mido, lecture/ecriture de fichiers, wxformbuilder, tkinter, python basique sans bibliotheques,mobile andriod, jeux…) Idem pour le discord de ce que j’en ai vu (jetez un œil au discord de godot francophone qui n’est pas parfeit mais qui a plusieurs sous catégories dans la partie entre-aide)</li>
<li>Pourquoi pas aussi une catégorie sur les idées d’améliorations, les questions concernant le site (ou l’afpy en général)<br/>
Je ne sais pas trop ou poster donc je poste ici mais si ca peu donner des idées…<br/>
Au revoir.</li>
</ul>
<p><small>5 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/questions-idees-dameliorations-et-quelques-petits-trucs/2545">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Musclor13</name>
        </author>
    </entry>
    <entry>
        <title>PEP 751 acceptée -- Python a désormais un &#34;lockfile&#34; standard</title>
        <link href="https://linuxfr.org/users/linkdd/liens/pep-751-acceptee-python-a-desormais-un-lockfile-standard" />
        <id>https://linuxfr.org/users/linkdd/liens/pep-751-acceptee-python-a-desormais-un-lockfile-standard</id>
        <updated>2025-03-31T16:13:58Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://peps.python.org/pep-0751/">https://peps.python.org/pep-0751/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138760/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/linkdd/liens/pep-751-acceptee-python-a-desormais-un-lockfile-standard#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>David Delassus</name>
        </author>
    </entry>
    <entry>
        <title>Probleme wxformbuilder, wxpython et print()</title>
        <link href="https://discuss.afpy.org/t/probleme-wxformbuilder-wxpython-et-print/2544" />
        <id>https://discuss.afpy.org/t/probleme-wxformbuilder-wxpython-et-print/2544</id>
        <updated>2025-03-30T21:47:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour.<br/>
J’ai pas l’habitude de poster sur des forums car en général y a tout ce qu’il faut sur internet mais la…<br/>
Je me suis amusé a créé une simple fenêtre et un bouton avec wxformbuilder que j’ai convertis ensuite en code wxpython. J’ai créé un 2eme script pour ouvrir la fenêtre que j’ai créé. Comme j’avais indiqué dans Event une class a OnButtonClic mon fichier wx généré contenais a la fin:</p>
<pre><code class="lang-python">    # Virtual event handlers, override them in your derived class
    def clicsurlebouton( self, event ):
        event.Skip()

</code></pre>
<p>J’ai copié/collé dans mon fichier qui sert a ouvrir la fenêtre et j’ai mis un print() a la place du event.Skip().<br/>
Voici la totalité de mon code “a la main”</p>
<pre><code class="lang-python"># -*- coding: utf-8 -*-
import wx
import wx.xrc

import genwx


app = wx.App()
genwx.Fenetre(None).Show()


def clicsurlebouton( self, event ):
    print("Clic sur bouton")
    return

print("avant MainLoop")

app.MainLoop()

print("apres MainLoop")

</code></pre>
<p>Quand je lance ce script la console affiche bien</p>
<pre><code class="lang-python">avant MainLoop
</code></pre>
<p>mais plus rien ensuite et le bouton n’affiche rien…<br/>
Avez-vous une idée?<br/>
Je débute en wxpython mais j’aipas mal essayé des petits trucs avec l’IDLE et python en général.<br/>
J’ajoute que plus tard j’aimerais utiliser des scripts créés avant en remplaçant certaines variable par ce que l’utilisateur définis dans l’interface graphique puis en affichant le résultat dans la fenêtre et/ou dans print (ou en faisant l’action de lire ou d’écrire dans un fichier/variables par exemple)…<br/>
Bonne soirée.</p>
<p><small>12 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-wxformbuilder-wxpython-et-print/2544">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Musclor13</name>
        </author>
    </entry>
    <entry>
        <title>SVP arrêtez d&#39;utiliser Python pour vos logiciels en GUI.</title>
        <link href="https://linuxfr.org/users/totof2000-2/journaux/svp-arretez-d-utiliser-python-pour-vos-logiciels-en-gui" />
        <id>https://linuxfr.org/users/totof2000-2/journaux/svp-arretez-d-utiliser-python-pour-vos-logiciels-en-gui</id>
        <updated>2025-03-30T13:09:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Je n'irai pas jusque dire "arrêtez d'utiliser python" tout court mais je le pense fortement.</p>
<p>Je veux tester un outil appelé glogic.</p>
<p>Je l'installe via apt puis je tente de l'exécuter :</p>
<p>/usr/lib/python3/dist-packages/glogic/MainFrame.py:4: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '4.0') before import to ensure that the right version gets loaded.<br/>
  from gi.repository import Gtk, Gdk, GdkPixbuf<br/>
Traceback (most recent call last):<br/>
  File "/usr/bin/glogic", line 20, in <br/>
    from glogic.MainFrame import MainFrame<br/>
  File "/usr/lib/python3/dist-packages/glogic/MainFrame.py", line 18, in <br/>
    themed_icons = Gtk.IconTheme.get_default()<br/>
AttributeError: type object 'IconTheme' has no attribute 'get_default'<br/>
totof@superbipbip:~$ glogic</p>
<p>Ca donne vraiment pas envie …</p>
<p>Alors oui on me dira certainement que c'est pas un problème python mais un problème GTK, qu'avec un autre langage ce serait la même chose mais je suis quasi certain que dans ce cas de figure le problème vient surtout de la façon dont Python gère ses dépendances. </p>
<div><a href="https://linuxfr.org/users/totof2000-2/journaux/svp-arretez-d-utiliser-python-pour-vos-logiciels-en-gui.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138742/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/totof2000-2/journaux/svp-arretez-d-utiliser-python-pour-vos-logiciels-en-gui#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>totof2000</name>
        </author>
    </entry>
    <entry>
        <title>Dernières nouvelles et fonctionnalités de Canaille</title>
        <link href="https://yaal.coop/blog/canaille-nlnet-features-releases" />
        <id>https://yaal.coop/blog/canaille-nlnet-features-releases</id>
        <updated>2025-03-27T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Nos dernières nouvelles</h1>
<p>L'année 2024 s'est terminée avec de nombreux nouveaux développements sur Canaille, financés par <a href="https://nlnet.nl/">NLNet</a> ! Vous pouvez en lire plus à ce sujet sur <a href="https://yaal.coop/blog/canaille-nlnet-security-features">l'article de blog dédié à ces développements</a>. Nous avons poursuivi ces développements, toujours grâce au même financement. Lisez la suite pour en savoir plus !</p>
<h2>Audit de sécurité et correctifs</h2>
<p>Un audit de sécurité a été conduit par <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a> courant février, avec pour objectif la découverte de potentielles failles dans notre produit, et l'implémentation de correctifs avant la fin mars.</p>
<h3>Amélioration de la sécurité de la réinitialisation du mot de passe</h3>
<p>L'ajout de la variable de configuration de flask <code>TRUSTED_HOSTS</code> (<a href="https://flask.palletsprojects.com/en/stable/config/#TRUSTED_HOSTS">documentation ici</a>) évite à nos liens magiques d'inscription et de réinitialisation de mot de passe d'être falsifiés par des hôtes malveillants.</p>
<p>Nous avons également amélioré la façon dont ces liens sont générés pour les rendre plus sécurisés et leur implémenter une durée de validité définie.</p>
<h3>Vulnérabilité de récupération de logo</h3>
<p>Nous avons corrigé une vulnérabilité qui aurait pu théoriquement permettre la falsification de requêtes serveur (SSRF) au moment de récupérer le logo de l'application.</p>
<h3>Meilleure validation d'URL</h3>
<p>La validation de l'adresse de site internet d'utilisateur a été améliorée, elle est mainteant plus restrictive.</p>
<h3>Implémentation de la Content Security Policy</h3>
<p>Content Security Policy (CSP) a été implémentée dans Canaille via <a href="https://github.com/GoogleCloudPlatform/flask-talisman">Flask-Talisman</a>. CSP rend notre application plus robuste, notamment face aux attaques "cross-site scripting" (XSS).</p>
<h2>Certification OIDC</h2>
<p>Le processus de certification OpenID a été beaucoup plus complexe que prévu pour notre équipe. Nous avons fait de nombreux progrès et implémenté de nombreuses fonctionnalités liées à OpenID, dans le but d'obtenir la certification et d'en faire passer les tests automatisés. Dans ce cadre, nous avons contribué et soulevé des <em>issues</em> chez <a href="https://github.com/lepture/authlib/issues">Authlib</a>, pour un meilleur support de la spécification OpenID en amont.</p>
<p>Nous avons notamment :</p>
<ul>
<li>Implémenté la spécification sur la validation d'URIs de redirection</li>
<li>Mis à jour nos modèles pour implémenter les attribus requis par OIDC.</li>
<li>Affiché les liens vers les conditions d'utilisation et les politiques de confidentialité lorsque le client demandant l'autorisation nous les fournit.</li>
<li>Affiché la plupart des erreurs de requête en format JSON.</li>
<li>Implémenté les réponses au format JSON Web Token lorsque le client le requiert.</li>
<li>Amélioré la gestion des JWT et des JWKS  de Canaille.</li>
</ul>
<h2>Paquets : Image Docker</h2>
<p>Canaille peut être testé plus facilement grâce à la création d'une image docker, hébergée sur un répertoire public. Les utilisateurs peuvent découvrir Canaille avec un profil administrateur.</p>
<p><em>La création de cette image docker a été rendue possible par la construction d'un paquet nix.</em></p>
<h2>Audit d'accessibilité et améliorations</h2>
<p>Canaille a bénéficié d'un audit d'accessibilité conduit par <a href="https://www.hanuniversity.com/en/">HAN accessibility lab</a>. Les résultats ont souligné plusieurs problèmes de contrastes ainsi qu'un manque de différenciation entre les liens et le texte non interactif, et quelques soucis de navigation au clavier.</p>
<h3>Améliorations d'accessibilité</h3>
<ul>
<li>La plupart des soucis de contraste ont été corrigés.</li>
<li>La plupart des soucis de différentiation des liens et des éléments interactifs ont été corrigés.</li>
<li>Un lien d'évitement a été ajouté en haut de chaque page.</li>
</ul>
<h2>Approvisionnement SCIM</h2>
<p>Canaille fournissait déjà une implémentation de serveur SCIM depuis notre <a href="https://yaal.coop/blog/en/canaille-nlnet-security-features">dernière mise à jour de sécurité</a>. Maintenant, l'application dispose également des fonctionnalités de client SCIM, permettant à une instance Canaille de propager automatiquement les changements d'utilisateurs et de groupes aux applications client. Cette fonctionnalité devrait rendre plus simple le maintien de la synchronisation entre toutes les applications sans plus d'intervention utilisateur.</p>
<hr/>
<p>Merci de nous avoir lu ! Nous vous tiendrons au courant de nos prochaines avancées, et vous pouvez dès maintenant lire nos autres contributions au logiciel libre dans nos articles de contributions saisonnières.</p>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>New features and latest news on Canaille</title>
        <link href="https://yaal.coop/blog/en/canaille-nlnet-features-releases" />
        <id>https://yaal.coop/blog/en/canaille-nlnet-features-releases</id>
        <updated>2025-03-27T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Our latest news</h1>
<p>2024 ended with a lot of new developments on Canaille, funded by <a href="https://nlnet.nl/">NLNet</a>. You can read it all on <a href="https://yaal.coop/blog/canaille-nlnet-security-features">our dedicated blog post</a>. We went through another round of developments, still under the same fund. You can read it all on this page!</p>
<h2>Security audit and improvements</h2>
<p>Canaille started 2025 with a security audit, conducted by <a href="https://www.radicallyopensecurity.com/">Radically Open Security</a>. Our main objectives were to know the weaknesses of our product and implement fixes before the end of march.</p>
<h3>Better password reset security</h3>
<p>The implementation of the flask <code>TRUSTED_HOSTS</code> (<a href="https://flask.palletsprojects.com/en/stable/config/#TRUSTED_HOSTS">see documentation here</a>) configuration variable prevents our "magic links" at user registration and password reset to be falsified and hijacked by a malicious host.</p>
<p>We also improved the way these links are generated to make them more secure and introduce a time limit in their validity.</p>
<h3>Logo retrieval vulnerability</h3>
<p>We removed a vulnerability that could theoretically permit a server-side request forgery (SSRF) when retrieving the logo of the application.</p>
<h3>Better user URL validation</h3>
<p>We improved the validation of the user website's URL to make it more restrictive.</p>
<h3>Implementation of Content Security Policy</h3>
<p>Content Security Policy (CSP) has been implemented on Canaille via <a href="https://github.com/GoogleCloudPlatform/flask-talisman">Flask-Talisman</a>. CSP makes it harder to disrupt our application, for example with cross-site scripting (XSS) attacks.</p>
<h2>OIDC Certification</h2>
<p>The OpenID Certification process was expected to be much less trouble than it was. We made a lot of progress on making the certification tests pass but still have a lot to do in order to be certified. We implemented features and fixes as well as raised issues and contributed to <a href="https://github.com/lepture/authlib/issues">Authlib</a> to get better support of the OpenID Specification.</p>
<p>Part of the progress done was:</p>
<ul>
<li>Match OIDC specification on redirect URIs validation.</li>
<li>Update our models to implement attributes required by OIDC.</li>
<li>Displaying Terms of Service and Privacy policy links if the client requesting authorization issues them.</li>
<li>Displaying most request errors as JSON error pages.</li>
<li>Responding with JSON web tokens when requested by the client.</li>
<li>Improvement on Canaille's handling of JWTs and JWKS.</li>
</ul>
<h2>Packaging: Docker image</h2>
<p>Canaille can be tested more easily thanks to a docker image hosted on a public hub docker repository. Users can discover Canaille via an administrator profile.</p>
<p><em>The creation of this docker image was made possible by building a nix package.</em></p>
<h2>Accessibility audit and improvements</h2>
<p>Canaille benefited from an Accessibility audit as well, conducted by <a href="https://www.hanuniversity.com/en/">HAN accessibility lab</a>. The results provided underlined several contrast issues and lack of differentiation of links from regular text, and a few keyboard navigation issues.</p>
<h3>Accessibility improvements</h3>
<ul>
<li>Most color contrast issues have been fixed.</li>
<li>Most link differentiation and visual changes on focus and hover have been fixed.</li>
<li>A skip link has been added at the top of every page.</li>
</ul>
<h2>SCIM Provisioning</h2>
<p>Canaille already provided a SCIM server implementation since our <a href="https://yaal.coop/blog/en/canaille-nlnet-security-features">last security update</a>. It now also supports SCIM client features, allowing a Canaille instance to automatically broadcast changes on users and groups to client applications. This should make it easier for all applications to remain synchronized without needing additional user intervention.</p>
<hr/>
<p>Thanks for reading, we will keep you updated on our next progress, and you can still read about our other free software contributions on our *seasonal contributions* blog posts.</p>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Typage python avec des tableaux numpy ou autre</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/typage-python-avec-des-tableaux-numpy-ou-autre" />
        <id>https://linuxfr.org/forums/programmation-python/posts/typage-python-avec-des-tableaux-numpy-ou-autre</id>
        <updated>2025-03-26T17:07:05Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je code une librairie python en utilisant les annotations de type. Elle manipule des tableaux numériques de type Numpy, PyTorch, …</p>
<p>Donc j'ai des fonctions qui peuvent prendre n'importe qu'elle type de tableau et je comprends pas comment faire les annotations. Pour le moment, je fais ça</p>
<pre><code class="python"><span class="n">Array</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Array"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">is_array</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TypeGuard</span><span class="p">[</span><span class="n">Array</span><span class="p">]:</span>
    <span class="sd">"""A TypeGuard for array-like objects."""</span>
    <span class="k">return</span> <span class="n">array_api_compat</span><span class="o">.</span><span class="n">is_array_api_obj</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">inarray</span><span class="p">:</span> <span class="n">Array</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Array</span><span class="p">:</span>
   <span class="o">...</span></code></pre>
<p>mais pyright me dit</p>
<blockquote>
<p>warning: TypeVar "Array" appears only once in generic function signature. Use "object" instead (reportInvalidTypeVarUse)</p>
</blockquote>
<p>Par ailleurs, j'utilise is_array dans mes fonctions </p>
<pre><code class="python"><span class="k">if</span> <span class="ow">not</span> <span class="n">is_array</span><span class="p">(</span><span class="n">inarray</span><span class="p">):</span>
    <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
        <span class="s2">"`inarray` must be a compatible with Array API Standard (eg. numpy, pytorch, ...)"</span>
    <span class="p">)</span>

<span class="n">des_choses_avec_inarray</span></code></pre>
<p>mais mypy me dit que inarray est de type Never (mais pas pyright)…</p>
<p>Bref, je suis un peu perdu, il semble que l'on rentre dans des subtilités hors de ma portée. Si vous pouvez m'aidez merci !</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/typage-python-avec-des-tableaux-numpy-ou-autre.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138700/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/typage-python-avec-des-tableaux-numpy-ou-autre#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>François</name>
        </author>
    </entry>
    <entry>
        <title>Besoin d’aide pour apprendre l’IA et le Machine Learning avec Python</title>
        <link href="https://discuss.afpy.org/t/besoin-d-aide-pour-apprendre-l-ia-et-le-machine-learning-avec-python/2536" />
        <id>https://discuss.afpy.org/t/besoin-d-aide-pour-apprendre-l-ia-et-le-machine-learning-avec-python/2536</id>
        <updated>2025-03-24T10:47:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>(sujet supprimé par son auteur)</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/besoin-d-aide-pour-apprendre-l-ia-et-le-machine-learning-avec-python/2536">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Malouek</name>
        </author>
    </entry>
    <entry>
        <title>Comment OpenDocument enregistre-t-il les cellules des tableurs (`odfpy`)</title>
        <link href="https://discuss.afpy.org/t/comment-opendocument-enregistre-t-il-les-cellules-des-tableurs-odfpy/2533" />
        <id>https://discuss.afpy.org/t/comment-opendocument-enregistre-t-il-les-cellules-des-tableurs-odfpy/2533</id>
        <updated>2025-03-22T22:57:14Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>Je tente de modifier des tableurs ODS existants pour remplir des cellules avec <code>odfpy</code> (paquet pas mis à jour récemment, mais ça a l’air d’être le plus stable et sérieux de PyPI néanmoins ?).</p>
<p>Mon postulat initial était que pour accéder à une cellule, il suffisait de parcourir les éléments du XML dans l’ordre : C5 serait donc la ligne à l’indice 4 (5) puis la colonne 2 (C).</p>
<p>Cette théorie marche bien tant qu’il n’y a pas de cellule fusionnée dans le document. Le cas contraire, ça se complique et je ne comprends plus grand chose.</p>
<p>J’ai fait un <a class="attachment" href="https://discuss.afpy.org/uploads/short-url/7emTTLEiX33jeicewvN4d8BC1Xm.ods">test.ods</a> et <a href="https://gitlab.com/-/snippets/4828675" rel="noopener nofollow ugc">un notebook ici</a> pour illustrer mon incompréhension. Cela montre que, après des cellules fusionnées (en ligne ou en colonne), les autres cellules subissent un offset, que je ne sais pas expliquer.</p>
<p></p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/0/0e8d7b4a953e76cebba36f488a00373cd1e3b301.png" title="image"><img alt="image" height="141" src="https://discuss.afpy.org/uploads/default/original/2X/0/0e8d7b4a953e76cebba36f488a00373cd1e3b301.png" width="535"/></a></div><p></p>
<p>Quelqu’un a-t-il déjà manipulé des ODS ainsi ?</p>
<p><small>7 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/comment-opendocument-enregistre-t-il-les-cellules-des-tableurs-odfpy/2533">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>yoan</name>
        </author>
    </entry>
    <entry>
        <title>homebrew et .venv</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/homebrew-et-venv" />
        <id>https://linuxfr.org/forums/programmation-python/posts/homebrew-et-venv</id>
        <updated>2025-03-21T19:36:58Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
lien présentation : <a href="https://linuxfr.org/forums/programmation-python/posts/je-me-presente">https://linuxfr.org/forums/programmation-python/posts/je-me-presente</a></p>
<p>Alors voilà, je suis sur un tuto YouTube d'assistant virtuel, et bien que j'ai énormément creusé, je souffre. C'est pourquoi je me suis inscrit.</p>
<p>OK pour l'install de packages en cascade…</p>
<p>Mais ma première question concerne le fait que après l'install d'un package réussie, il n'est pas forcément reconnu dans mon code (genre sur l'import, ou plutôt sur l'appel de certaines méthodes), bien qu'il soit présent dans le terminal.</p>
<p>En gros, j'ai bien compris ce que je ne comprenais pas.<br/>
2 sujets :<br/>
- les installs homebrew<br/>
- l'environnement virtuel</p>
<p>J'en dis pas plus pour ne pas surcharger.</p>
<p>Merci d'avance.</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/homebrew-et-venv.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138657/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/homebrew-et-venv#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>busterComanche</name>
        </author>
    </entry>
    <entry>
        <title>La nouvelle informatique</title>
        <link href="https://linuxfr.org/users/vendrediouletrollsauvage/liens/la-nouvelle-informatique-9be2203f-26b0-4703-8c03-94413de045e4" />
        <id>https://linuxfr.org/users/vendrediouletrollsauvage/liens/la-nouvelle-informatique-9be2203f-26b0-4703-8c03-94413de045e4</id>
        <updated>2025-03-21T09:14:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://ploum.net/2024-03-21-nouvelle-informatique.html">https://ploum.net/2024-03-21-nouvelle-informatique.html</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138644/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/vendrediouletrollsauvage/liens/la-nouvelle-informatique-9be2203f-26b0-4703-8c03-94413de045e4#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>volts</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;hiver 2025</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2025" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2025</id>
        <updated>2025-03-19T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://pypi.org/project/markdownmail/">MarkdownMail</a></h2>
<p><em>Bibliothèque d'envoi d'e-mails dont le contenu HTML est généré automatiquement</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/markdownmail/-/commit/317d667d2b4956b0bead0678f08a84545bf6b27e">Correction de la capture d'écran</a>, puis publication de la version 0.11.1.</li>
</ul>
<h2><a href="https://ergol.org/">Ergo-L</a></h2>
<p><em>Disposition de clavier optimisée pour le français, l’anglais et la programmation</em></p>
<ul>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/297">Correction du rendu du '^' comme touche</a></li>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/296">Ajout du besoin de <code>pandoc</code> pour générer le site web</a></li>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/300">Présentation minimale de l'usage sur la page d'accueil</a></li>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/301">Ajout de caractères manquants ('ß' et 'ñ' ) dans le fichier ergo.svg</a></li>
</ul>
<h2><a href="https://github.com/tushuhei/sphinxcontrib-screenshot">sphinxcontrib-screenshot</a></h2>
<p><em>Génération dynamique de captures d'écran pour les documentations Sphinx</em></p>
<ul>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/26">Ability to take screenshots from local WSGI applications</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/30">Pass import path instead of callable in `screenshot_apps</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/31">Python 3.12 and 3.13 GHA</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/33">Pre-commit configuration</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/34"><code>:color-scheme:</code> option</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/35">Tox configuration</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/36">Consider the color scheme when building the image hash</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/37">Implement default size configuration parameters</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/39">Move from setup.cfg to pyproject.toml</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/41">Allow <code>file://</code> url schemes</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/42">Use the raw URL value to build the image hash</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/43">Add a <code>screenshot_default_color_scheme</code> parameter</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/44">Add <code>:full-page:</code> option</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/45">Custom request headers</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/46">Custom contexts</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/48">Add <code>:browser:</code> option</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/49">Documentation creation</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/50">Documentation fixes</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/53">The <code>screenshot</code> directive inherits from <code>figure</code></a></li>
</ul>
<h2><a href="https://github.com/simon-weber/python-libfaketime">python-libfaketime</a></h2>
<p><em>Une alternative rapide à freezegun pour mocker les dates, en utilisant libfaketime</em></p>
<ul>
<li><a href="https://github.com/simon-weber/python-libfaketime/issues/85">Désactivation de <code>FAKETIME_FORCE_MONOTONIC_FIX</code></a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/issues/86">Mise-à-jour de pre-commit</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/issues/87">Support pour Python 3.13</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">Authlib</a></h2>
<p><em>Bibliothèque Python de gestion des identités et des accès</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/Authlib/#history">2 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/lepture/authlib/issues/701">Implémentation côté serveur de la spécification RFC9207</a></li>
<li><a href="https://github.com/lepture/authlib/issues/702">Ajout d'un paramètre <code>kid</code> à <code>generate_id_token</code></a></li>
<li><a href="https://github.com/lepture/authlib/issues/703">Migrate de flake8 vers ruff</a></li>
<li><a href="https://github.com/lepture/authlib/issues/706">Ajout de descriptions à <code>InvalidClientError</code> et <code>UnauthorizedClientError</code></a></li>
<li><a href="https://github.com/lepture/authlib/issues/707">Implémentation de la spécification « OpenID Connect Dynamic Client Registration »</a></li>
<li><a href="https://github.com/lepture/authlib/issues/708">Utilisation de groupes de dépendances pour les tests</a></li>
<li><a href="https://github.com/lepture/authlib/issues/715">Correction du paramètre <code>iss</code> de la RFC9207</a></li>
</ul>
<h2><a href="https://github.com/boxed/mutmut">mutmut</a></h2>
<p><em>Système de tests par mutations</em></p>
<ul>
<li><a href="https://github.com/boxed/mutmut/issues/363">Annotation des <code>dict</code> mutants pour corriger la compatibilité avec Pydantic</a></li>
<li><a href="https://github.com/boxed/mutmut/issues/364">Évite de muter les métaclasses</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-cli">scim2-cli</a></h2>
<p><em>Outil en ligne de commandes pour interagir avec des applications SCIM</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-cli/#history">1 nouvelle version</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-cli/issues/22">Implémentation du paramètre <code>--no-verify</code> pour éviter les vérifications de certificats</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-models/#history">1 nouvelle version</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/issues/89">Correction des limites basses de <code>startIndex</code> et <code>count</code></a></li>
<li><a href="https://github.com/python-scim/scim2-models/issues/90"><code>ListResponse.total_results</code> est un paramètre obligatoire</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Serveur d’identité et d'autorisations ultra-léger</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/canaille/#history">8 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/209">Option CLI <code>--version</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/211">Implémentation du paramètre <code>--all</code> de la commande <code>get</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/212">L'interface CLI peut afficher les mots de passes chiffrés</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/214">Migrations SQL avec flask-alembic</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/215">Correction du remplissage automatique du champs de mot de passe à la réinitialisation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/216">Intégration HTMX avec le formulaire de confirmation d'emails</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/217">Ajout automatique de captures d'écran dans la documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/219">Implementation de la commande <code>run</code> qui lance un serveur hypercorn</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/221">Le paramètre <code>SECRET_KEY</code> est facultatif</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/223">Commande d'export de la configuration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/224">Fichier unique exécutable</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/225">Correction de la commande d'installation en SQL</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/226">Correction de l'internationalisation dans l'exécutable unique</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/227">Paramètre <code>kid</code> dans le JWKS</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/228">Gestion du paramètre <code>jwks</code> lors de l'enregistremnet dynamique des clients OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/229">Implémentation de la RFC7523</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/232">Utilisation d'une image docker LDAP personnalisée pour la démo</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/233">Implémentation du paramètre de configuration <code>LOGIN_ATTRIBUTES</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/234">Implémentation de la norme « OIDC Dynamic Client Registration »</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/237">Émission de signaux lors des évènements importants des objets</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/238">Mise-à-jour vers Fomantic 2.9.4</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/242">Implémentation de RFC9207 avec Authlib</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/243">Renommage de <code>Client.preconsent</code> vers <code>Client.trusted</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/253">Maintien de l'ordre d'ajout dans les tables SQL relationnelles</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/255">Implémentation naïve de la commande <code>restore</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/256">La commande <code>delete</code> prends des paramètres de filtrage</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/257">Correction de la command <code>restore</code> avec LDAP et des données partielles</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/258">Les comptes verrouillés ne peuvent pas réinitialiser leurs mots de passe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/259">Suppression d'un correctif temporaire pour l'affichage d'icônes en CSS</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/260">Découverte automatique des serveurs SMTP locaux</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/261">Enrichissement des paramètres de permissions par défaut</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/262">Correction de diverses erreurs dans l'interface web lorsqu'un utilisateur n'a aucune adresse email définie</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/222">Résoud de l'enregistrement de clients sans périmètre</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/230">Correction: Autorise un client à accéder à "userinfo" avec le périmètre openid</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/239">Résoud "S'assurer que le lien de redirection du client ne contient pas de composant fragment à l'enregistrement"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/240">Correctif de sécurité : Il n'y a plus de lien magique dans la réinitisation de mot de passe si la variable TRUSTED_HOSTS n'est pas configurée</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/241">Résoud "Ensure authorization requests have a valid redirect URI"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/244">Résoud "Accessibilité : Ajout d'un lien d'évitement dans toutes les pages"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/245">Remplace la regec par urlparse dans validate_uri</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/246">Utilisation de HMAC pour construire les hashes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/248">Résoud "Accessibilité : Corrige le ratio de contraste sur les boutons et les textes"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/249">Amélioration de la lisibilité des paginations</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/251">Affiche les liens vers la politique de confidentialité et les conditions d'utilisation sur les pages d'autorisation client, si définis</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/252">Les erreurs d'URI avec fragments sont maintenant affichées en json</a></li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Ensemble d'outils et de bibliothèques pour la console PSP de Sony</em></p>
<ul>
<li><a href="https://github.com/pspdev/pspsdk/pull/260">Ajout de descriptions sur des bibliothèques</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Winter 2025 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2025" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2025</id>
        <updated>2025-03-19T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://pypi.org/project/markdownmail/">MarkdownMail</a></h2>
<p><em>Library to send e-mails with generated HTML content</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/markdownmail/-/commit/317d667d2b4956b0bead0678f08a84545bf6b27e">Fix screenshot picture</a>, then release 0.11.1.</li>
</ul>
<h2><a href="https://ergol.org/">Ergo-L</a></h2>
<p><em>Keyboard layout optimised for French, English and programming</em></p>
<ul>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/297">Fix '^' rendering as key pressed</a></li>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/296">Add <code>pandoc</code> requirement to generate the website</a></li>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/300">Explain basic usage on the homepage</a></li>
<li><a href="https://github.com/Nuclear-Squid/ergol/pull/301">Add missing characters ('ß' and 'ñ' ) in ergo.svg file</a></li>
</ul>
<h2><a href="https://github.com/tushuhei/sphinxcontrib-screenshot">sphinxcontrib-screenshot</a></h2>
<p><em>Generate dynamic screenshots in Sphinx documentation</em></p>
<ul>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/26">Ability to take screenshots from local WSGI applications</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/30">Pass import path instead of callable in `screenshot_apps</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/31">Python 3.12 and 3.13 GHA</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/33">Pre-commit configuration</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/34"><code>:color-scheme:</code> option</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/35">Tox configuration</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/36">Consider the color scheme when building the image hash</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/37">Implement default size configuration parameters</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/39">Move from setup.cfg to pyproject.toml</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/41">Allow <code>file://</code> url schemes</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/42">Use the raw URL value to build the image hash</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/43">Add a <code>screenshot_default_color_scheme</code> parameter</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/44">Add <code>:full-page:</code> option</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/45">Custom request headers</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/46">Custom contexts</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/48">Add <code>:browser:</code> option</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/49">Documentation creation</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/50">Documentation fixes</a></li>
<li><a href="https://github.com/tushuhei/sphinxcontrib-screenshot/issues/53">The <code>screenshot</code> directive inherits from <code>figure</code></a></li>
</ul>
<h2><a href="https://github.com/simon-weber/python-libfaketime">python-libfaketime</a></h2>
<p><em>A fast time mocking alternative to freezegun that wraps libfaketime.</em></p>
<ul>
<li><a href="https://github.com/simon-weber/python-libfaketime/issues/85">Disable FAKETIME_FORCE_MONOTONIC_FIX</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/issues/86">Pre-commit update</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/issues/87">Python 3.13 support</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.</em></p>
<p>We published <a href="https://pypi.org/project/Authlib/#history">2 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/lepture/authlib/issues/701">Server-side RFC9207 implementation</a></li>
<li><a href="https://github.com/lepture/authlib/issues/702"><code>kid</code> parameter for <code>generate_id_token</code></a></li>
<li><a href="https://github.com/lepture/authlib/issues/703">Migrate from flake8 to ruff</a></li>
<li><a href="https://github.com/lepture/authlib/issues/706">Add descriptions to <code>InvalidClientError</code> and <code>UnauthorizedClientError</code></a></li>
<li><a href="https://github.com/lepture/authlib/issues/707">OpenID Connect Dynamic Client Registration</a></li>
<li><a href="https://github.com/lepture/authlib/issues/708">Use dependency groups for tests</a></li>
<li><a href="https://github.com/lepture/authlib/issues/715">Fix RFC9207 <code>iss</code> parameter</a></li>
</ul>
<h2><a href="https://github.com/boxed/mutmut">mutmut</a></h2>
<p><em>Mutation testing system</em></p>
<ul>
<li><a href="https://github.com/boxed/mutmut/issues/363">Annotate mutant dicts and solve Pydantic compatibility</a></li>
<li><a href="https://github.com/boxed/mutmut/issues/364">Avoid to mutate metaclasses</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-cli">scim2-cli</a></h2>
<p><em>SCIM application development CLI</em></p>
<p>We published <a href="https://pypi.org/project/scim2-cli/#history">1 release</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-cli/issues/22">Implement <code>--no-verify</code> to avoid perform certificate checks</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<p>We published <a href="https://pypi.org/project/scim2-models/#history">1 release</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/issues/89">Fix startIndex and count lower limits</a></li>
<li><a href="https://github.com/python-scim/scim2-models/issues/90">ListResponse.total_results is required</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">Canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<p>We published <a href="https://pypi.org/project/canaille/#history">8 releases</a> during this season.</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/209"><code>--version</code> CLI option</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/211">feat: implement <code>--all</code> option of <code>get</code> command</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/212">CLI commands can dump hashed passwords</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/214">SQL migrations with flask-alembic</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/215">Fix password field auto-refilling when input is reset</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/216">HTMX integration with the email confirmation form</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/217">Add automatic screenshots in the documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/219">Implement <code>run</code> server command based on hypercorn</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/221"><code>SECRET_KEY</code> is optional</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/223">Configuration export CLI</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/224">Single binary bundle</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/225">SQL install command fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/226">Fix bring i18n in the Canaille executable</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/227">Fix dynamic <code>kid</code> parameter for JWKs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/228"><code>jwks</code> parameter management with OIDC client dynamic registration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/229">Implement RFC7523 client JWT authentication and grant</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/232">Use a custom LDAP docker image for the demo</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/233">Implement the <code>LOGIN_ATTRIBUTES</code> configuration parameter</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/234">Full OIDC Dynamic Client Registration implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/237">Signals on object lifetime events</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/238">Update to Fomantic 2.9.4</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/242">Implement RFC9207 with authlib</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/243">Rename <code>Client.preconsent</code> in <code>Client.trusted</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/253">Order SQL relationship tables</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/255">Naive <code>restore</code> command implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/256">The delete command can take filter parameters</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/257">Fix the LDAP restore command with partial payloads</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/258">Prevent locked accounts from resetting their password</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/259">Remove CSS action label icons hotfix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/260">Automatic discovery of local SMTP server</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/261">Set-up good default ACLs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/262">Fix various crashes in the web interface when users have no email configured</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/222">Resolve "Handle registration of clients without scopes"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/230">fix: allows client to access userinfo with openid scope</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/239">Resolve "Ensure that client redirection URI does not have a fragment component at registration"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/240">Security fix : magic link is not anymore in reset password e-mails unless TRUSTED_HOSTS is configured</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/241">Resolve "Ensure authorization requests have a valid redirect URI"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/244">Resolve "Accessibility : Add a skip link in base template"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/245">Replace regex with urlparse in validate_uri</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/246">Use HMAC to build hashes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/248">Resolve "Accessibility : Fix contrast ratio on buttons and text"</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/249">Improve pagination legibility</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/251">Display policy and terms of service uri in client authorization page if set</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/252">URI with fragments error at client registration now returns a json error page</a></li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Collection of tools and libraries written for Sony's Playstation Portable (PSP) gaming console</em></p>
<ul>
<li><a href="https://github.com/pspdev/pspsdk/pull/260">Add description to libraries</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris — Meetup le 14 mai</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai/2530" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai/2530</id>
        <updated>2025-03-19T17:35:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>J’ai reçu un message d’Édith (<a href="https://www.pycon.fr/2023/fr/talks/1h.html#documentation-logiciel-libre-e">Documentation, logiciel libre et pérennité en arts numériques</a> @ PyConFR 2023) qui passe sur Paris, c’est donc l’occasion de faire un meetup !</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai/2530/1">Sur Paris — Meetup le 14 mai</a></p>
<p>2025-05-14 19:00 (Europe/Paris) → 2025-05-14 22:00 (Europe/Paris)</p>
</div>
<p>Reste à trouver un lieu <img alt=":smiley:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiley.png?v=12" title=":smiley:" width="20"/></p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai/2530">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Sur Paris — Meetup le 14 mai à l&#39;April</title>
        <link href="https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai-a-lapril/2530" />
        <id>https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai-a-lapril/2530</id>
        <updated>2025-03-19T17:35:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>J’ai reçu un message d’Édith (<a href="https://www.pycon.fr/2023/fr/talks/1h.html#documentation-logiciel-libre-e">Documentation, logiciel libre et pérennité en arts numériques</a> @ PyConFR 2023) qui passe sur Paris, c’est donc l’occasion de faire un meetup !</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai-a-lapril/2530/1">Sur Paris — Meetup le 14 mai à l'April</a></p>
<p>2025-05-14 19:00 (Europe/Paris) → 2025-05-14 22:00 (Europe/Paris)</p>
</div>
<p>Lieu : locaux de l’April, 44/46 rue de l’Ouest, Bâtiment 8, 75014 Paris (voir la localisation sur <a href="https://www.openstreetmap.org/export/embed.html?bbox=2.318026721477509%2C48.83606581491022%2C2.320424616336823%2C48.837485234375855&amp;layer=mapnik&amp;marker=48.836775529670504%2C2.3192256689071655">OpenStreetMap</a>).</p>
<p><small>16 messages - 6 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-paris-meetup-le-14-mai-a-lapril/2530">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>`is_prime(n)` distrayants ?</title>
        <link href="https://discuss.afpy.org/t/is-prime-n-distrayants/2528" />
        <id>https://discuss.afpy.org/t/is-prime-n-distrayants/2528</id>
        <updated>2025-03-19T13:12:26Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Je trouve « distrayant » cette implèm de <code>is_prime</code> :</p>
<pre><code class="lang-python">from itertools import count


def gen_primes():
    for i in count(1):
        if is_prime(i):
            yield i


def is_prime(i):
    if i &lt; 3:
        return i == 2
    for d in gen_primes():
        if d ** 2 &gt; i:
            return True
        if i % d == 0:
            return False
</code></pre>
<p>C’est le côté « Bah ça peut pas marcher : <code>is_prime</code> a besoin de <code>gen_primes</code> mais <code>gen_primes</code> a besoin de <code>is_prime</code>. » suivi de « OMG ça marche en fait ! » que je trouve distrayant ici.</p>
<p>je me demande s’il existe d’autres implémentation « distrayantes », soit de <code>is_prime</code>, soit d’un autre algo d’ailleurs.</p>
<p>À vos clavier <img alt=":smiley:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiley.png?v=12" title=":smiley:" width="20"/></p>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/is-prime-n-distrayants/2528">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Aide pour script imap2mbox</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/aide-pour-script-imap2mbox" />
        <id>https://linuxfr.org/forums/programmation-python/posts/aide-pour-script-imap2mbox</id>
        <updated>2025-03-16T22:22:35Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je n'y connais rien en Python, c'est juste que je n'ai que des appareils Android et un serveur Web, je voudrais sauvegarder mes courriels en .mbox et tout ce que j'ai trouvé que je puisse lancer est un script Python <a href="https://zerozone.it/Software/Linux/imap2mbox/">https://zerozone.it/Software/Linux/imap2mbox/</a></p>
<p>Sauf que sur mon serveur python2 imap2mbox.py donne:</p>
<blockquote>
<p>ERROR: IMAP4 error SSLError(1, u'[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:727)')</p>
</blockquote>
<p>et pypthon3 ou 3.6 où je pensais SSL plus à jour donne:</p>
<blockquote>
<p>File "imap2mbox.py", line 50<br/>
parser.error("Argument 'mailsrv' missing: -m [your_mail_server]")</p>
</blockquote>
<p>Et je n'arrive pas à corriger le script pour mettre les paramètres directement ou qu'ils soient pris en compte.</p>
<p>De l'aide?<br/>
Ou une autre solution pour IMAP vers .mbox?</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/aide-pour-script-imap2mbox.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138596/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/aide-pour-script-imap2mbox#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Djik</name>
        </author>
    </entry>
    <entry>
        <title>Écriture collaborative implémenté en Django + React</title>
        <link href="https://discuss.afpy.org/t/ecriture-collaborative-implemente-en-django-react/2521" />
        <id>https://discuss.afpy.org/t/ecriture-collaborative-implemente-en-django-react/2521</id>
        <updated>2025-03-16T20:19:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <aside class="onebox githubrepo">
<header class="source">
<a href="https://github.com/suitenumerique/docs" rel="noopener" target="_blank">github.com</a>
</header>
<article class="onebox-body">
<div class="github-row">
<img class="thumbnail" height="344" src="https://opengraph.githubassets.com/e17055bc1e1ed95338ad5d5de983d2e4/suitenumerique/docs" width="690"/>
<h3><a href="https://github.com/suitenumerique/docs" rel="noopener" target="_blank">GitHub - suitenumerique/docs: A collaborative note taking, wiki and...</a></h3>
<p><span class="github-repo-description">A collaborative note taking, wiki and documentation platform that scales. Built with Django and React. Opensource alternative to Notion or Outline.</span></p>
</div>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/ecriture-collaborative-implemente-en-django-react/2521">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Quelqu&#39;un de dispo pour m&#39;aider à me lancer?</title>
        <link href="https://discuss.afpy.org/t/quelquun-de-dispo-pour-maider-a-me-lancer/2499" />
        <id>https://discuss.afpy.org/t/quelquun-de-dispo-pour-maider-a-me-lancer/2499</id>
        <updated>2025-03-15T07:20:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>ça fait un moment que je compte monter en compétence sur python et le destin semble me forcer un peu la main ces derniers temps.<br/>
un ami à moi à besoin d’une aide urgente pour un projet sur lequel il travaillait en collaboration avec un partenaire qui s’est retirer à un moment crucial, et qui gérait la partie technique…<br/>
il me demande de l’aide car je gravite dans le milieu IT depuis 15ans (chefferie de projet ERP).</p>
<p>dans l’urgence, je dois lui trouver une solution pour retraiter des fichiers excel et csv:</p>
<ul>
<li>pour collecter des informations et les regrouper dans un unique fichier unique</li>
<li>pour éclater des lignes et écrire dans un autre csv</li>
</ul>
<p>pyhon me semble tout indiquer pour cela. j’ai commencé à me documenter. je commence à comprendre l’algo à écrire, mais j’ai des questions sur tout ce qui concerne l’archi, le framework, les répertoires…</p>
<p>j’ai commencé à regardé VS code.</p>
<p>pour donner des infos sur mon profil:<br/>
j’ai fait du dèv il y a quelques années mais c’était dans SAP, donc langage propriétaire : on gère tout directement dans l’ERP (dèv + paramétrage), donc je n’ai jamais eu besoin de sortir de l’appli pour développer et structurer les choses)</p>
<p>quelqu’un aurait-il un peu de temps à m’accorder pour échanger en visio ou en présentiel, (je compenserai l’aide par un apéro <img alt=":wink:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/wink.png?v=12" title=":wink:" width="20"/> )<br/>
je suis dans le nord, entre Lille et Lens. je peux me déplacer.</p>
<p>l’idée est d’échanger pour me mettre sur les bons rails et aller plus vite (mon ami a des échéances trés proches, et un budget largement surconsommé par l’ancien tech).</p>
<p>pas de meet-up sur lille dommage.</p>
<p>hâte d’échanger avec quelqu’un.</p>
<p>Gauthier_B.</p>
<p><small>23 messages - 8 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/quelquun-de-dispo-pour-maider-a-me-lancer/2499">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Gauthier_B</name>
        </author>
    </entry>
    <entry>
        <title>Administrateur système et devops F/H</title>
        <link href="https://discuss.afpy.org/t/administrateur-systeme-et-devops-f-h/2497" />
        <id>https://discuss.afpy.org/t/administrateur-systeme-et-devops-f-h/2497</id>
        <updated>2025-03-14T10:38:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://makina-corpus.com" rel="noopener nofollow ugc">Makina Corpus</a> conçoit et développe des projets web ou mobiles d’envergure qui allient notamment la cartographie, l’intelligence artificielle, le traitement et l’analyse de données, la dataviz etc.<br/>
Nos solutions innovantes, construites sur des logiciels libres,  s’attaquent aux défis cruciaux de la transition numérique : mobilité,  environnement, santé, aménagement du territoire et développement durable.</p>
<p>Nos actions reposent sur <strong>trois piliers fondamentaux</strong> :<br/>
• Logiciels Libres : Nous privilégions des solutions ouvertes et accessibles ;<br/>
• Respect de l’Humain : Chaque projet est conçu avec une approche centrée sur l’utilisateur ;<br/>
• Engagement Environnemental : Nous nous engageons à minimiser notre impact écologique, soutenus par notre charte RSE.</p>
<p>Découvrez notre univers et [nos projets] et n’hésitez pas à nous suivre sur <a href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Welcome To The Jungle</a>.</p>
<p><strong>La mission :</strong><br/>
Vous rejoindrez l’équipe responsable de l’exploitation du système d’information de Makina Corpus, moderne, automatisé et basé à 100 % sur des logiciels libres. Makina Corpus héberge la majorité des services qu’elle utilise tel qu’une instance de GitLab, une registry Docker, des services de messagerie instantané, partage et édition collaborative de documents, CRM, etc.</p>
<p>Votre rôle transverse sur les projets vous permettra d’aborder de nombreuses technologies et d’interagir avec une équipe interdisciplinaire (ergonome, graphistes, développeurs Back/Front, SIG, DBA, mobile…), répartie entre Toulouse, Nantes et Paris.</p>
<p><strong>Vos missions en ingénierie infrastructure/administration système et devops</strong> consisteront à :</p>
<p><strong>1) Exploiter le SI de la société</strong> (partie administration systèmes):<br/>
• Assurer le suivi des mises à jour de nos outils et services internes, les maintenir en condition opérationnelle<br/>
• Gérer la sécurité des serveurs qui supportent l’infra (Debian et Ubuntu, LXC)<br/>
• Maintenir et faire évoluer les rôles Ansible permettant la gestion automatisée de la configuration des machines<br/>
• Superviser les environnements clients (préproduction et production)<br/>
• Assurer une veille technologique et proposer et faire évoluer l’infrastructure existante ainsi que nos processus de déploiement suivant les bonnes pratiques<br/>
• Développer des outils d’aide aux tâches d’administration système et de supervision</p>
<p><strong>2) Orchestrer le déploiement de nos applications métiers</strong> (partie devops) :<br/>
• Mettre en œuvre et optimiser les processus d’intégration et de déploiement de nos applications métiers Python/Django et PHP (Drupal/Symfony) en fonction des spécificités et besoins des développeurs par le biais de l’intégration continue/déploiement continu (GitLab-CI, Ansible)<br/>
• Conseiller et assister les équipes de développement sur les bonnes pratiques liées au déploiement, aux solutions techniques et enjeux de performance et de sécurité en production<br/>
• Maintenir et faire évoluer des outils, modèles et bases de projet, documentations à destination des développeurs pour les accompagner dans la livraison des applications.</p>
<p><strong>Vous aurez l’opportunité de :</strong><br/>
• Choisir vos propres outils de travail, et évoluer dans une ambiance motivante et stimulante (projets et contributions à des logiciels libres, participations encouragées à des évènements/meetup, émulation entre experts passionnés, technologies innovantes à tester, veille…)<br/>
• Évoluer dans environnement technique interdisciplinaire permettant à chacun d’avoir un véritable impact sur les décisions et où l’initiative personnelle est valorisée.<br/>
• Évoluer dans une organisation du travail en mode hybride (mix présentiel-télétravail)<br/>
• Participer activement à la vie de l’entreprise : avec vos collègues, vous la représenterez au sein de la communauté<br/>
• Jouer un rôle visible dans les communautés des logiciels libres : création et amélioration de logiciels libres / Participation à la vie de communautés de développeurs / Coordination de sprints, de bugfests / Réalisation de présentations, conférences, bar camps, formations, lightning talks / Écriture de livres blancs…</p>
<p><em>Ce poste est ouvert au télétravail partiel (jusqu’à 3 jours/semaine).</em></p>
<p><strong>Le profil</strong></p>
<p>Vous avez d’excellentes connaissances et une <strong>expérience de 4 ans minimum</strong> dans l’administration de systèmes Linux (Debian/Ubuntu) ainsi que dans ces technologies :<br/>
• Écosystème Docker (conteneurs, registry, orchestration)<br/>
• Intégration continue GitLab-CI<br/>
• Gestion de configuration avec Ansible</p>
<p>Ainsi qu’une connaissance des technologies suivantes:<br/>
• PostgreSQL<br/>
• Scripting bash<br/>
• Prometheus/Grafana<br/>
• API REST<br/>
• Kubernetes</p>
<p>Une connaissance des langages de programmation Python et PHP serait un véritable avantage.</p>
<p>Vous savez travailler en équipe, à distance et en mode asynchrone dans l’objectif d’évangéliser, expliquer et transmettre. Vous savez être force de proposition sur les solutions techniques mises en œuvre.</p>
<p>Faire évoluer vos connaissances pour apprendre de nouvelles techniques vous stimule, <strong>vous êtes curieux et appréciez de sortir de votre zone de confort.</strong></p>
<p><strong>Informations complémentaires</strong><br/>
Vous contribuerez activement aux valeurs humaines ancrées dans l’ADN de l’entreprise (environnement, équilibre vie pro/vie privée - grâce à la souplesse des horaires et au télétravail encadré -, travail collaboratif, solide couverture santé…) même si nous n’avons pas du tout la prétention d’être parfaits…</p>
<p>Vous avez besoin de le voir pour le croire ? Venez nous rencontrer, un.e makinien.ne pourra vous en parler  !<br/>
Nos équipes sont mixtes, femmes du numérique rejoignez-nous !</p>
<p>Écrivez-nous et racontez qui vous êtes et ce qui vous anime. Expliquez-nous en quoi vos motivations et vos compétences sont en adéquation avec nos valeurs et nos activités.</p>
<p>Nous répondons à chacune des candidatures de manière personnalisée et dans un délai que nous essayons de rendre le plus raisonnable possible. Si votre candidature est sélectionnée, voici comment cela va se passer pour vous :<br/>
• un 1° échange en visio vous sera proposé par Lise notre RRH afin de faire plus ample connaissance et de déterminer si vous, comme nous, souhaitons aller plus loin ;<br/>
• il y aura ensuite un 2° entretien avec un expert de l’équipe technique et un chef de projet : ce sera l’occasion de parler technique, missions et projets ;<br/>
• enfin, vous serez reçu.e par la responsable de l’agence.</p>
<p>La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/administrateur-systeme-et-devops-f-h/2497">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>Problème avec broche du raspberry 4</title>
        <link href="https://discuss.afpy.org/t/probleme-avec-broche-du-raspberry-4/2493" />
        <id>https://discuss.afpy.org/t/probleme-avec-broche-du-raspberry-4/2493</id>
        <updated>2025-03-12T21:23:13Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonsoir,<br/>
Quelqu’un pourrait-il me dire où se trouve la broche n°1 sur la raspberry 4B, avec une image et une flèche si possible indiquant où… .<br/>
J’ai bien noté que la soudure de la broche n°1 a une base carrée, cependant, meme en examinant attentativement , je trouve les bases des soudures toutes pareilles…<br/>
</p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/1/1b4dfd4f35a049199be71d8a8e7f8efb3ba53dbb.png" title="11"><img alt="11" height="392" src="https://discuss.afpy.org/uploads/default/original/2X/1/1b4dfd4f35a049199be71d8a8e7f8efb3ba53dbb.png" width="580"/></a></div><p></p>
<p>Merci d’avance pour l’aide</p>
<p><small>10 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-avec-broche-du-raspberry-4/2493">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Cavok</name>
        </author>
    </entry>
    <entry>
        <title>Process ended with exit code 0.</title>
        <link href="https://discuss.afpy.org/t/process-ended-with-exit-code-0/2492" />
        <id>https://discuss.afpy.org/t/process-ended-with-exit-code-0/2492</id>
        <updated>2025-03-12T17:44:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, je suis lycéen en classe de première et j’ai pour projet noté de reproduire un jeu, j’ai donc choisi Snake, cependant, chaque fois que j’atteins un certains endroit proche de la bordure cela s’arrête avec le message ‘Process ended with exit code 0.’, je ne comprend pas pourquoi sachant que les bordure sont définis sur <code>0&lt;Zone jouable&lt;1000</code> pour <code>x</code> et <code>0&lt;Zone Jouable&lt;750</code> pour <code>y</code>, si qq pourrait m’aider svp et m’expliquer comment ne plus croiser cette erreur</p>
<pre><code class="lang-python">import pygame


pygame.init()

def affiche(S):
    # affiche tous les pixels du serpent
    # a partir de leurs coordonnees dans S
    for coord in S:
      x,y = coord
      pygame.draw.rect(dis, blue, [x, y, 50, 50])
    pygame.display.flip()
 
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
green = (138,169,14)
blue = (10,74,130)
 
dis = pygame.display.set_mode((1001, 836))
 
game_over = False
 
x1 = 300
y1 = 300
 
x1_change = 0       
y1_change = 0
 
clock = pygame.time.Clock()

serpent = [[400,200],[450,200],[500,200] ]
serpent2 = [(450,250)]
      
while not game_over:
    fond = pygame.image.load('font_overlay.png')
    fond = fond.convert()
    dis.blit(fond, (0,0))
    affiche(serpent)
    #pygame.display.update()
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            game_over = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                x1_change = -50
                y1_change = 0
            elif event.key == pygame.K_RIGHT:
                x1_change = 50
                y1_change = 0
            elif event.key == pygame.K_UP:
                y1_change = -50
                x1_change = 0
            elif event.key == pygame.K_DOWN:
                y1_change = 50
                x1_change = 0
            
            
            
            serpent.pop()
            tete = [serpent[0][0]+x1_change,serpent[0][1]+y1_change]
            serpent.insert(0,tete)
            
    x1 += x1_change
    y1 += y1_change
    
    # collisions
    # bordures
    if serpent[0][0]+x1_change &lt; 0 or serpent[0][0]+x1_change &gt; 1000 :
        pygame.time.wait(1000)
        game_over = True
    if serpent[0][0]+y1_change &lt; 0 or serpent[0][0]+y1_change &gt; 750 :
        pygame.time.wait(1000)
        game_over = True
    # self_eating

    
    affiche(serpent)
    pygame.display.update()
 
    clock.tick(60)

pygame.quit()
quit()
</code></pre>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/process-ended-with-exit-code-0/2492">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Matyss</name>
        </author>
    </entry>
    <entry>
        <title>Un plugin pytest pour démarrer une instance Netbox lors de vos suites de test</title>
        <link href="https://linuxfr.org/users/linkdd/liens/un-plugin-pytest-pour-demarrer-une-instance-netbox-lors-de-vos-suites-de-test" />
        <id>https://linuxfr.org/users/linkdd/liens/un-plugin-pytest-pour-demarrer-une-instance-netbox-lors-de-vos-suites-de-test</id>
        <updated>2025-03-11T17:27:32Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://github.com/link-society/pytest-netbox-docker">https://github.com/link-society/pytest-netbox-docker</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138552/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/linkdd/liens/un-plugin-pytest-pour-demarrer-une-instance-netbox-lors-de-vos-suites-de-test#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>David Delassus</name>
        </author>
    </entry>
    <entry>
        <title>Python mal installé</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/python-mal-installe" />
        <id>https://linuxfr.org/forums/programmation-python/posts/python-mal-installe</id>
        <updated>2025-03-11T10:25:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour et déjà merci pour votre aide.<br/>
Par ailleurs, je ne sais pas si je suis au bon endroit pour poser ma question… si pas mes excuses et merci de me donner des pistes de réflexions.<br/>
Voici donc mon problème : je pense que mon logiciel Python est installé au mauvais endroit voici le path ~/.cache/activestate/bin <br/>
Quand je veux utiliser pip install pour ajouter des bibliothèques, le système m'envoie des erreurs.<br/>
Quand je veux passer à la version python3.13 et que je lui demande de l'installer dans un répertoire :~/PYTHON$, je me retrouve avec la version 3.10.</p>
<p>J'avoue que je suis un peu perdu Pourquoi mon programme est-il dans un répertoire caché (/.cache) serait-ce la cause du problème et comment puis-je disposer de la dernière version de Python et pouvoir utiliser les extensions via pip ?</p>
<p>Pour information, je suis sous UBUNTU 24.4 et je programme en Python via VSCode</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/python-mal-installe.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138549/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/python-mal-installe#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>chahit</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 20 mars</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-20-mars/2487" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-20-mars/2487</id>
        <updated>2025-03-10T11:01:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>Prochain meetup Python à Lyon jeudi 20 mars à 19h !</p>
<p>Emma nous parlera des outils utilisant Python dans la typographie, de la conception à la post-production <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=12" title=":snake:" width="20"/></p>
<p>Pour ce meetup, nous sommes accueillis par LeBureau.coop (métro Jean Macé).</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-20-mars/2487/1">Python dans la typographie: de la conception à la post-production</a></p>
<p>2025-03-20 19:00 (Europe/Paris) → 2025-03-20 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-20-mars/2487">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Difficile de recommander Python en production</title>
        <link href="https://linuxfr.org/users/woffer/liens/difficile-de-recommander-python-en-production" />
        <id>https://linuxfr.org/users/woffer/liens/difficile-de-recommander-python-en-production</id>
        <updated>2025-03-08T07:10:24Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://ashishb.net/programming/python-in-production/">https://ashishb.net/programming/python-in-production/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138518/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/woffer/liens/difficile-de-recommander-python-en-production#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>woffer 🐧</name>
        </author>
    </entry>
    <entry>
        <title>marimo : The future of Python notebooks</title>
        <link href="https://linuxfr.org/users/pas_pey/liens/marimo-the-future-of-python-notebooks" />
        <id>https://linuxfr.org/users/pas_pey/liens/marimo-the-future-of-python-notebooks</id>
        <updated>2025-03-07T13:11:39Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://marimo.io">https://marimo.io</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138514/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/pas_pey/liens/marimo-the-future-of-python-notebooks#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>pas_pey</name>
        </author>
    </entry>
    <entry>
        <title>Chef.Cheffe de projets web: climat, agriculture et environnement – Toulouse - CDI</title>
        <link href="https://discuss.afpy.org/t/chef-cheffe-de-projets-web-climat-agriculture-et-environnement-toulouse-cdi/2485" />
        <id>https://discuss.afpy.org/t/chef-cheffe-de-projets-web-climat-agriculture-et-environnement-toulouse-cdi/2485</id>
        <updated>2025-03-07T11:25:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><strong>Rejoignez Makina Corpus</strong> en tant que Chef-Cheffe de projets web spécialisé(e) dans les domaines du climat, de l’agriculture et de l’environnement. Intégrez une équipe engagée qui développe des solutions numériques innovantes en combinant cartographie, intelligence artificielle et analyse de données pour répondre aux enjeux environnementaux majeurs.</p>
<p>Vous travaillerez sur des projets qui font sens tels que la gestion d’espaces naturels et l’aménagement du territoire, en accord avec nos valeurs historiques : logiciels libres, respect de l’humain et engagement écologique. En tant que membre de notre équipe, vous participerez activement à la conception et à la coordination de projets web d’envergure, tout en bénéficiant d’un environnement de travail stimulant qui valorise la collaboration et l’innovation. <strong>Si vous êtes motivé par l’idée de contribuer à des projets ayant un impact positif sur le monde</strong>, nous serions ravis de vous accueillir chez Makina Corpus.</p>
<p><em>Découvrez quelques uns de nos projets : <a class="inline-onebox" href="https://makina-corpus.com/references" rel="noopener nofollow ugc">Références | Makina Corpus</a>, et retrouvez-nous sur Welcome To The Jungle (<a class="inline-onebox" href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Makina Corpus : photos, vidéos, recrutement</a>).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-10050-la-mission-1" name="p-10050-la-mission-1"></a>La mission</h2>
<p><strong>Vous intégrerez un pôle interdisciplinaire (chefs de projets, ergonomes, graphistes, développeurs Back/Front/Mobile, SIG, DBA…) réparti entre Toulouse, Nantes et Paris, au sein duquel vous aurez pour mission de piloter les projets de nos clients et de participer de façon active au développement commercial.</strong></p>
<p><strong><strong>Vos missions consisteront à :</strong></strong></p>
<ul>
<li>Identifier et mettre en œuvre au sein du projet les <strong>besoins technico-fonctionnels</strong> des clients</li>
<li>Formaliser, organiser, planifier et contrôler les phases de réalisation</li>
<li><strong>Piloter et coordonner</strong> l’équipe projet</li>
<li>Assurer le suivi du planning et le contrôle de la qualité</li>
<li>Gérer les <strong>engagements vis-à-vis du client</strong> et s’assurer de sa satisfaction</li>
<li><strong>Fidéliser</strong>, entretenir et développer le portefeuille client existant</li>
<li><strong>Participer aux phases d’avant-vente en relation avec le client et avec nos équipes, rédiger une proposition commerciale</strong></li>
</ul>
<p><em>Nous mettrons en place un plan de formation</em> <em>et un accompagnement par plusieurs chefs de projets</em> <em>adapté pour vous permettre d’acquérir rapidement une très bonne connaissance de l’entreprise, son activité et son environnement, et de vous approprier et maîtriser le</em> <strong>s techniques de gestion de projet web exigeants.</strong></p>
<p><em>Ce poste est ouvert au télétravail partiel (jusqu’à 3 jours/semaine).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-10050-profil-2" name="p-10050-profil-2"></a>Profil</h2>
<p><em>Vous maîtrisez les méthodes et outils de gestion de projets web complexes et techniques, et</em> <em><strong>possédez</strong></em> <em><strong>une expérience de minimum 2 ans sur ce type de poste.</strong></em></p>
<p><em>Vous possédez un</em> <em><strong>background technique dans le développement web.</strong></em></p>
<p><em>Vous avez une appétence commerciale et idéalement une expérience dans la réponse à appels d’offres.</em></p>
<ul>
<li>Vous aimez comprendre les besoins du client, s’approprier son métier et lui proposer des solutions adaptées ;</li>
<li>Votre goût du travail en équipe, votre curiosité, vos excellentes qualités relationnelles seront des atouts indispensables. Apprendre toujours plus vous stimule !</li>
</ul>
<p><em>Nous ne précisons pas de diplôme ou de niveau d’études minimum</em> <em>car nous attachons avant tout de l’importance aux compétences et à la passion du métier.</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-10050-informations-complmentaires-3" name="p-10050-informations-complmentaires-3"></a>Informations complémentaires</h2>
<p>Dans la ruche collaborative Makina Corpus, <strong>on dit ce qu’on fait</strong> : les makiniens évoluent dans une ambiance motivante et stimulante (projets et contrib opensource, participations encouragées à des évènements/meetup, émulation entre experts passionnés, technos innovantes à tester, veille…) et contribuent aux valeurs humaines ancrées dans l’ADN de l’entreprise (environnement, équilibre vie pro/vie privée, collaboratif, télétravail…).</p>
<p>Mais surtout chez Makina <strong>on fait ce qu’on dit</strong> : vous avez besoin de le voir pour le croire ? Venez nous rencontrer, un.e makinien.ne pourra vous en parler ! Nos équipes sont mixtes, femmes et hommes du numérique nous vous attendons.</p>
<p><strong>Écrivez-nous et racontez qui vous êtes et ce qui vous anime</strong>. Expliquez-nous en quoi vos motivations et vos compétences sont en adéquation avec nos valeurs et nos activités.</p>
<p><strong>En savoir plus sur notre processus de recrutement :</strong></p>
<p><strong>Nous répondons à chacune des candidatures de manière personnalisée et dans un délai que nous essayons de rendre le plus raisonnable possible. Si votre candidature est sélectionnée, voici comment cela va se passer pour vous :</strong></p>
<ul>
<li>un 1° échange en visio vous sera proposé par Lise notre RRH afin de faire plus ample connaissance et de déterminer si vous, comme nous, souhaitons aller plus loin ;</li>
<li>il y aura ensuite un 2° entretien avec 2 chefs de projet toulousains : ce sera l’occasion de parler du poste, des missions et des projets ;</li>
<li>enfin, vous serez reçu.e par le responsable de l’agence.</li>
</ul>
<p>La décision finale sera prise collectivement par vos différents interlocuteurs. Tout au long du parcours, vous serez en lien direct avec Lise.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/chef-cheffe-de-projets-web-climat-agriculture-et-environnement-toulouse-cdi/2485">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>Comment utiliser Hyperfine ?</title>
        <link href="https://www.olivierpons.fr/2025/03/01/comment-utiliser-hyperfine/" />
        <id>https://www.olivierpons.fr/2025/03/01/comment-utiliser-hyperfine/</id>
        <updated>2025-03-01T16:31:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <article>
<header>
<h1>Comment utiliser Hyperfine pour comparer les performances de rg et ag</h1>
</header>
<section>
<h2>Qu’est-ce que Hyperfine ?</h2>
<p>Hyperfine est un outil en ligne de commande qui permet de mesurer et de comparer les performances d’autres commandes. Il est particulièrement utile pour évaluer la vitesse d’exécution de différentes commandes ou scripts, en fournissant des statistiques détaillées comme le temps moyen, l’écart-type, et la plage de temps d’exécution.</p>
</section>
<section>
<h2>Présentation de rg (ripgrep)</h2>
<p>Ripgrep, souvent abrégé en <code>rg</code>, est un outil de recherche de texte ultra-rapide. Il est conçu pour parcourir rapidement des fichiers et des répertoires à la recherche de motifs spécifiques. Ripgrep est connu pour sa rapidité et sa capacité à ignorer les fichiers non pertinents, comme ceux dans les répertoires <code>.git</code> ou <code>node_modules</code>.</p>
</section>
<section>
<h2>Présentation de ag (The Silver Searcher)</h2>
<p>The Silver Searcher, ou <code>ag</code>, est un autre outil de recherche de texte, similaire à <code>ack</code>, mais plus rapide. Il est optimisé pour la recherche dans des projets de code, en ignorant automatiquement les fichiers et répertoires non pertinents. Bien qu’il soit rapide, il est souvent surpassé par <code>rg</code> en termes de performances.</p>
</section>
<section>
<h2>Comparaison des performances avec Hyperfine</h2>
<p>Pour comparer les performances de <code>rg</code> et <code>ag</code>, nous pouvons utiliser Hyperfine avec la commande suivante :</p>
<pre><code>hyperfine --warmup 3 'rg -i "Olivier" -g "*php*" .' 'ag -i "Olivier" -G "php"'</code></pre>
<p>Les résultats montrent que <code>rg</code> est significativement plus rapide que <code>ag</code> :</p>
<ul>
<li><code>rg</code> a un temps moyen d’exécution de 256.6 ms.</li>
<li><code>ag</code> a un temps moyen d’exécution de 910.3 ms.</li>
</ul>
<p>En résumé, <code>rg</code> est environ 3.55 fois plus rapide que <code>ag</code> dans ce scénario.</p>
</section>
<section>
<h2>Pourquoi utiliser rg plutôt que ag ?</h2>
<p>La comparaison effectuée avec Hyperfine démontre clairement que <code>rg</code> est plus performant que <code>ag</code> pour la recherche de texte. Si la vitesse est un critère important pour vous, <code>rg</code> est donc un choix évident. De plus, <code>rg</code> offre une meilleure gestion des fichiers ignorés et une intégration plus fluide avec les outils modernes de développement.</p>
</section>
<footer>En conclusion, si vous cherchez un outil de recherche de texte rapide et efficace, <code>rg</code> est une excellente option, surtout lorsque vous travaillez sur des projets de grande envergure où chaque milliseconde compte.
</footer>
</article>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Connaissez le temps de reboot de vos machines ?</title>
        <link href="https://bearstech.com/blog/connaissez-le-temps-de-reboot-de-vos-machines" />
        <id>https://bearstech.com/blog/connaissez-le-temps-de-reboot-de-vos-machines</id>
        <updated>2025-03-01T09:23:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>vcaron</name>
        </author>
    </entry>
    <entry>
        <title>Connaissez-vous le temps de reboot de vos machines ?</title>
        <link href="https://bearstech.com/blog/connaissez-vous-le-temps-de-reboot-de-vos-machines" />
        <id>https://bearstech.com/blog/connaissez-vous-le-temps-de-reboot-de-vos-machines</id>
        <updated>2025-03-01T09:23:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>vcaron</name>
        </author>
    </entry>
    <entry>
        <title>[Django] Détecter une migration manquante via les tests unitaires</title>
        <link href="https://linuxfr.org/users/killruana/journaux/django-detecter-une-migration-manquante-via-les-tests-unitaires" />
        <id>https://linuxfr.org/users/killruana/journaux/django-detecter-une-migration-manquante-via-les-tests-unitaires</id>
        <updated>2025-02-28T10:17:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Django a un chouette système de <a href="https://docs.djangoproject.com/en/5.1/topics/migrations/">migrations</a> pour répercuter sur la db les changements effectués sur les modèles.</p>
<p>Mais des fois, oups, on oublie de déclarer les nouvelles migrations.</p>
<p>Avec ce simple test case, vous pouvez détecter le problème via les tests unitaires et ainsi vous assurez que votre CI/CD ne déploit jamais du code où les modèles ne sont plus synchronisés par rapport à la db.</p>
<pre><code class="python"><span class="c1">#  DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE </span>
<span class="c1">#                     Version 2, December 2004 </span>
<span class="c1">#</span>
<span class="c1">#  Copyright (C) 2004 Sam Hocevar &lt;sam@hocevar.net&gt; </span>
<span class="c1">#</span>
<span class="c1">#  Everyone is permitted to copy and distribute verbatim or modified </span>
<span class="c1">#  copies of this license document, and changing it is allowed as long </span>
<span class="c1">#  as the name is changed. </span>
<span class="c1">#</span>
<span class="c1">#             DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE </span>
<span class="c1">#    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION </span>
<span class="c1">#</span>
<span class="c1">#   0. You just DO WHAT THE FUCK YOU WANT TO.</span>

<span class="kn">from</span> <span class="nn">django.core.management</span> <span class="kn">import</span> <span class="n">call_command</span>
<span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">TestCase</span>


<span class="k">class</span> <span class="nc">MissingMigrationTestCase</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_is_a_migration_missing</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">call_command</span><span class="p">(</span><span class="s2">"makemigrations"</span><span class="p">,</span> <span class="s2">"--check"</span><span class="p">,</span> <span class="s2">"--verbosity=0"</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">SystemExit</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">fail</span><span class="p">(</span><span class="s2">"You have updated the models but forget to create a migration."</span><span class="p">)</span></code></pre>
<p>Démo :</p>
<pre><code class="shell">$ ./manage.py <span class="nb">test</span> tests.windfit.models.test_missing_migration.MissingMigrationTestCase.test_is_a_migration_missing
Found <span class="m">1</span> test<span class="o">(</span>s<span class="o">)</span>.
Creating <span class="nb">test</span> database <span class="k">for</span> <span class="nb">alias</span> <span class="s1">'default'</span>...
System check identified no issues <span class="o">(</span><span class="m">0</span> silenced<span class="o">)</span>.
<span class="nv">F</span>
<span class="o">======================================================================</span>
FAIL: test_is_a_migration_missing <span class="o">(</span>tests.windfit.models.test_missing_migration.MissingMigrationTestCase.test_is_a_migration_missing<span class="o">)</span>
----------------------------------------------------------------------
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"/home/jtremesay/projects/webfit/tests/windfit/models/test_missing_migration.py"</span>, line <span class="m">8</span>, in test_is_a_migration_missing
    call_command<span class="o">(</span><span class="s2">"makemigrations"</span>, <span class="s2">"--check"</span>, <span class="s2">"--verbosity=0"</span><span class="o">)</span>
    ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File <span class="s2">"/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/__init__.py"</span>, line <span class="m">194</span>, in call_command
    <span class="k">return</span> command.execute<span class="o">(</span>*args, **defaults<span class="o">)</span>
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File <span class="s2">"/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/base.py"</span>, line <span class="m">459</span>, in execute
    <span class="nv">output</span> <span class="o">=</span> self.handle<span class="o">(</span>*args, **options<span class="o">)</span>
  File <span class="s2">"/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/base.py"</span>, line <span class="m">107</span>, in wrapper
    <span class="nv">res</span> <span class="o">=</span> handle_func<span class="o">(</span>*args, **kwargs<span class="o">)</span>
  File <span class="s2">"/home/jtremesay/projects/webfit/.direnv/python-3.13/lib/python3.13/site-packages/django/core/management/commands/makemigrations.py"</span>, line <span class="m">261</span>, in handle
    sys.exit<span class="o">(</span><span class="m">1</span><span class="o">)</span>
    ~~~~~~~~^^^
SystemExit: <span class="m">1</span>

During handling of the above exception, another exception occurred:

Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
  File <span class="s2">"/home/jtremesay/projects/webfit/tests/windfit/models/test_missing_migration.py"</span>, line <span class="m">10</span>, in test_is_a_migration_missing
    self.fail<span class="o">(</span><span class="s2">"You have updated the models but forget to create a migration."</span><span class="o">)</span>
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: You have updated the models but forget to create a migration.

----------------------------------------------------------------------
Ran <span class="m">1</span> <span class="nb">test</span> in <span class="m">0</span>.246s

FAILED <span class="o">(</span><span class="nv">failures</span><span class="o">=</span><span class="m">1</span><span class="o">)</span>
Destroying <span class="nb">test</span> database <span class="k">for</span> <span class="nb">alias</span> <span class="s1">'default'</span>...</code></pre>
<div><a href="https://linuxfr.org/users/killruana/journaux/django-detecter-une-migration-manquante-via-les-tests-unitaires.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138417/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/killruana/journaux/django-detecter-une-migration-manquante-via-les-tests-unitaires#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>jtremesay</name>
        </author>
    </entry>
    <entry>
        <title>Automatiser le nettoyage des branches Git avec un alias : Guide pratique</title>
        <link href="https://www.olivierpons.fr/2025/02/26/automatiser-le-nettoyage-des-branches-git-avec-un-alias-guide-pratique/" />
        <id>https://www.olivierpons.fr/2025/02/26/automatiser-le-nettoyage-des-branches-git-avec-un-alias-guide-pratique/</id>
        <updated>2025-02-26T16:23:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Automatiser le nettoyage des branches Git avec un alias : Guide pratique</h1>
<p>Travailler avec Git implique souvent de gérer de nombreuses branches, locales et distantes. Au fil du temps, il est courant que des branches distantes soient supprimées, laissant des branches locales obsolètes. Pour simplifier le nettoyage de ces branches, vous pouvez créer un alias Git qui automatise ce processus. Dans cet article, nous vous expliquons comment faire, ainsi que les avantages et les inconvénients de cette méthode.</p>
<h2>Créer un alias Git pour nettoyer les branches locales</h2>
<p>Voici la commande pour créer un alias Git nommé <code>prune-all</code> qui nettoie automatiquement les branches locales obsolètes :</p>
<pre><code>git config --global alias.prune-all '!git fetch --prune &amp;&amp; git branch -vv | grep ": gone]" | sed "s/^[[:space:]]*\([^[:space:]]*\).*/\1/" | xargs -r git branch -d'
</code></pre>
<p>Une fois cet alias configuré, vous pouvez simplement exécuter :</p>
<pre><code>git prune-all</code></pre>
<p>Cette commande va :</p>
<ol>
<li>Mettre à jour les références locales et supprimer les branches distantes supprimées (<code>git fetch --prune</code>).</li>
<li>Identifier les branches locales qui n’ont plus de branche distante associée (<code>git branch -vv | grep ": gone]"</code>).</li>
<li>Extraire les noms de ces branches (<code>sed</code>).</li>
<li>Supprimer les branches locales (<code>xargs -r git branch -d</code>).</li>
</ol>
<h2>Pourquoi utiliser cet alias ?</h2>
<p>Cet alias offre plusieurs avantages :</p>
<ul>
<li><strong>Gain de temps</strong> : Plus besoin d’exécuter manuellement plusieurs commandes pour nettoyer les branches locales.</li>
<li><strong>Automatisation</strong> : Le processus est entièrement automatisé, ce qui réduit les erreurs humaines.</li>
<li><strong>Propreté du dépôt</strong> : Vous gardez votre dépôt local propre et synchronisé avec le dépôt distant.</li>
</ul>
<h2>Les précautions à prendre</h2>
<p>Bien que cet alias soit très utile, il est important de comprendre ses limites et les risques potentiels :</p>
<ul>
<li><strong>Utilisation de <code>git branch -d</code></strong> : L’alias utilise <code>git branch -d</code> pour supprimer les branches locales. Cela signifie que Git refusera de supprimer une branche si elle contient des commits non fusionnés. C’est une sécurité pour éviter de perdre du travail.</li>
<li><strong>Risque de suppression accidentelle</strong> : Si vous utilisez <code>git branch -D</code> (avec un <code>D</code> majuscule) à la place de <code>-d</code>, les branches seront supprimées de force, même si elles contiennent des commits non fusionnés. Soyez prudent si vous modifiez l’alias pour utiliser <code>-D</code>.</li>
<li><strong>Vérification manuelle</strong> : Avant d’exécuter l’alias, il peut être utile de vérifier les branches qui seront supprimées en exécutant :</li>
</ul>
<pre><code>git fetch --prune &amp;&amp; git branch -vv | grep ": gone]"</code></pre>
<h2>Quand utiliser cet alias ?</h2>
<p>Cet alias est particulièrement utile dans les situations suivantes :</p>
<ul>
<li>Vous travaillez sur un projet avec de nombreuses branches, et vous voulez garder votre dépôt local propre.</li>
<li>Vous collaborez avec une équipe et les branches distantes sont fréquemment supprimées après fusion.</li>
<li>Vous voulez automatiser une tâche répétitive pour gagner du temps.</li>
</ul>
<h2>Conclusion</h2>
<p>Créer un alias Git pour nettoyer les branches locales est une excellente façon d’automatiser une tâche fastidieuse et de garder votre dépôt propre. En utilisant <code>git branch -d</code>, vous ajoutez une couche de sécurité pour éviter de perdre du travail non fusionné. Cependant, soyez conscient des risques si vous décidez d’utiliser <code>git branch -D</code> à la place.</p>
<p>N’hésitez pas à essayer cet alias et à l’adapter à vos besoins. Bonne gestion de branches !</p>
<p><strong>Vous avez des questions ou des suggestions ? Laissez un commentaire ci-dessous !</strong></p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>De l&#39;art avec du python</title>
        <link href="https://discuss.afpy.org/t/de-lart-avec-du-python/2481" />
        <id>https://discuss.afpy.org/t/de-lart-avec-du-python/2481</id>
        <updated>2025-02-25T20:18:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>C’est tout simple et vachement bien pensé ;o)</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="32" src="https://earth.hoyd.net/wp-content/uploads/fbrfg/favicon-32x32.png" width="32"/>
<a href="https://earth.hoyd.net/posts/seven-python-turtle-one-liners/" rel="noopener" target="_blank">Patterns, Code &amp; Curiosity</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img class="thumbnail" height="500" src="https://earth.hoyd.net/wp-content/uploads/2025/02/image-3.png" width="512"/></div>
<h3><a href="https://earth.hoyd.net/posts/seven-python-turtle-one-liners/" rel="noopener" target="_blank">Seven Python Turtle One-liners</a></h3>
<p>Turtle is a graphics framework in the standard Python library. Run these seven one-liners for some nice looking line art that should be framed: $ python -c "from turtle import *;tracer(0);[fd(x+30) or rt(45) for x in range(250)];exitonclick()"$...</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/de-lart-avec-du-python/2481">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Mindiell</name>
        </author>
    </entry>
    <entry>
        <title>Écran Noir (Black Screen) – un outil simple mais utile</title>
        <link href="https://www.olivierpons.fr/2025/02/24/ecran-noir-black-screen-un-outil-simple-mais-utile/" />
        <id>https://www.olivierpons.fr/2025/02/24/ecran-noir-black-screen-un-outil-simple-mais-utile/</id>
        <updated>2025-02-24T20:43:05Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Écran Noir (Black Screen) – Un outil simple mais utile</h2>
<p>J’ai récemment ajouté une fonctionnalité simple mais pratique à mon site : une page « Écran Noir » accessible à l’adresse <a href="https://www.olivierpons.fr/black-screen.html">olivierpons.fr/black-screen</a>.</p>
<h3>Qu’est-ce que c’est ?</h3>
<p>Il s’agit simplement d’une page web complètement noire, sans aucun élément d’interface ou contenu visible. Elle a été conçue pour afficher un écran noir pur qui occupe la totalité de votre navigateur.</p>
<h3>À quoi ça sert ?</h3>
<p>Cette page peut être utilisée dans plusieurs situations pratiques :</p>
<ol>
<li><strong>Présentations et conférences</strong> : Pour faire une pause entre deux diapositives ou temporairement masquer votre écran.</li>
<li><strong>Économie d’énergie</strong> : Un écran noir consomme moins d’énergie sur les écrans OLED/AMOLED.</li>
<li><strong>Réduction de la luminosité</strong> : Dans un environnement sombre, quand vous avez besoin d’une source de lumière minimale.</li>
<li><strong>Tests d’affichage</strong> : Pour vérifier les fuites de lumière ou la qualité du noir sur votre écran.</li>
<li><strong>Méditation ou concentration</strong> : Éliminer les distractions visuelles pendant une session de concentration.</li>
</ol>
<h3>Comment ça fonctionne ?</h3>
<p>Techniquement, c’est une simple page HTML statique avec un fond noir qui occupe 100% de l’écran et désactive le défilement. Elle est servie directement par Nginx sans passer par WordPress.</p>
<p>Cette solution a été implémentée avec l’aide de Claude, l’assistant IA d’Anthropic, qui m’a guidé dans la configuration Nginx et la création du fichier HTML approprié.</p>
<p>N’hésitez pas à l’utiliser quand vous en avez besoin, c’est un petit outil sans prétention mais qui peut s’avérer étonnamment utile !</p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Comment j&#39;ai testé FLOZz Daily Mix avec Nextcloud Music (Docker), Pytest, Nox et GitHub Actions</title>
        <link href="https://linuxfr.org/users/flozz/liens/comment-j-ai-teste-flozz-daily-mix-avec-nextcloud-music-docker-pytest-nox-et-github-actions" />
        <id>https://linuxfr.org/users/flozz/liens/comment-j-ai-teste-flozz-daily-mix-avec-nextcloud-music-docker-pytest-nox-et-github-actions</id>
        <updated>2025-02-24T06:13:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://blog.flozz.fr/2025/02/23/comment-jai-teste-flozz-daily-mix-avec-nextcloud-music-docker-pytest-nox-et-github-actions/">https://blog.flozz.fr/2025/02/23/comment-jai-teste-flozz-daily-mix-avec-nextcloud-music-docker-pytest-nox-et-github-actions/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138349/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/flozz/liens/comment-j-ai-teste-flozz-daily-mix-avec-nextcloud-music-docker-pytest-nox-et-github-actions#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>FLOZz</name>
        </author>
    </entry>
    <entry>
        <title>Problème pour demarrer un code avec Python</title>
        <link href="https://discuss.afpy.org/t/probleme-pour-demarrer-un-code-avec-python/2479" />
        <id>https://discuss.afpy.org/t/probleme-pour-demarrer-un-code-avec-python/2479</id>
        <updated>2025-02-19T12:32:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, j’essaie de faire un suivi d’objet avec une webcam, et je recopie un code ,cependant quand j’essaie d’installer cv2 d’open cv, je n’obtiens que des erreurs…<br/>
étant débutant en python, je pense que quelque chose m’échappe,<br/>
je vous mets ce que j’ai à ma disposition (le forum dit que je peux n’en mettre qu’un seul, aussi j’ai regroupé 2 images )<br/>
Merci pour vos conseils<br/>
</p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/5/569fff24860ff7a0e1b83a7c3fb9d7fd184e3490.png" title="Capture d’écran code et resultat"><img alt="Capture d’écran code et resultat" height="342" src="https://discuss.afpy.org/uploads/default/optimized/2X/5/569fff24860ff7a0e1b83a7c3fb9d7fd184e3490_2_690x342.png" width="690"/></a></div><p></p>
<p><small>38 messages - 7 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-pour-demarrer-un-code-avec-python/2479">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Cavok</name>
        </author>
    </entry>
    <entry>
        <title>Tkinter et scrollbar</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/tkinter-et-scrollbar" />
        <id>https://linuxfr.org/forums/programmation-python/posts/tkinter-et-scrollbar</id>
        <updated>2025-02-18T18:43:22Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Je suis content de mon code et je cherche à mettre plus d'équipes dorénavant.<br/>
Du coup, j'aurais besoin de rajouter une scrollbar sur la fenêtre principale; quelqu'un saurait faire?</p>
<p><a href="https://framagit.org/vev/elo-lvgsports">https://framagit.org/vev/elo-lvgsports</a> <br/>
"Elo LVGsports.py"</p>
<p>ps: pour faire marcher le code sur gnu/linux il faut changer le \ en / ligne 299<br/>
ps2: vous pouvez rajouter des joueurs dans le fichier "joueurs.json"<br/>
<code>exemple avec 24 joueurs nommés 0001, 0002 etc..<br/>
{"0001": ["1500", "0", "0", "0", "aucun enregistrement"], "0002": ["1500", "0", "0", "0", "aucun enregistrement"], "0003": ["1500", "0", "0", "0", "aucun enregistrement"], "0004": ["1500", "0", "0", "0", "aucun enregistrement"], "0005": ["1500", "0", "0", "0", "aucun enregistrement"], "0006": ["1500", "0", "0", "0", "aucun enregistrement"], "0007": ["1500", "0", "0", "0", "aucun enregistrement"], "0008": ["1500", "0", "0", "0", "aucun enregistrement"], "0009": ["1500", "0", "0", "0", "aucun enregistrement"], "0010": ["1500", "0", "0", "0", "aucun enregistrement"], "0011": ["1500", "0", "0", "0", "aucun enregistrement"], "0012": ["1500", "0", "0", "0", "aucun enregistrement"], "0013": ["1500", "0", "0", "0", "aucun enregistrement"], "0014": ["1500", "0", "0", "0", "aucun enregistrement"], "0015": ["1500", "0", "0", "0", "aucun enregistrement"], "0016": ["1500", "0", "0", "0", "aucun enregistrement"], "0017": ["1500", "0", "0", "0", "aucun enregistrement"], "0018": ["1500", "0", "0", "0", "aucun enregistrement"], "0019": ["1500", "0", "0", "0", "aucun enregistrement"], "0020": ["1500", "0", "0", "0", "aucun enregistrement"],"0021": ["1500", "0", "0", "0", "aucun enregistrement"], "0022": ["1500", "0", "0", "0", "aucun enregistrement"], "0023": ["1500", "0", "0", "0", "aucun enregistrement"], "0024": ["1500", "0", "0", "0", "aucun enregistrement"]}<br/>
</code></p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/tkinter-et-scrollbar.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138307/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/tkinter-et-scrollbar#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>vev</name>
        </author>
    </entry>
    <entry>
        <title>Mettre en lien une scène 3D Blender et une interface GTK | wxPython grâce à UPBGE</title>
        <link href="https://discuss.afpy.org/t/mettre-en-lien-une-scene-3d-blender-et-une-interface-gtk-wxpython-grace-a-upbge/2477" />
        <id>https://discuss.afpy.org/t/mettre-en-lien-une-scene-3d-blender-et-une-interface-gtk-wxpython-grace-a-upbge/2477</id>
        <updated>2025-02-17T16:47:16Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
Une petite démo sur la possibilité d’avoir une fenêtre externe (GUI) pour interagir avec une scène 3D Blender grâce au moteur de jeu <a href="https://upbge.org" rel="noopener nofollow ugc">UPBGE</a>.</p>
<p>J’utilise <a href="https://www.gtk.org/" rel="noopener nofollow ugc">GTK3+</a> pour GNU/Linux et <a href="https://www.wxpython.org/" rel="noopener nofollow ugc">wxPython</a> pour Windows. C’est tout à fait possible avec PySide, Kyvi, … tant que c’est en Python.</p>
<p>Le code est sur <a href="https://forge.apps.education.fr/blender-edutech/lecteur-3d-cinematique/lecteur-3d-cinematique" rel="noopener nofollow ugc">La Forge</a>. C’est un projet de Lecteur 3D pour l’analyse cinématique des mécanismes (que j’utilise avec mes élèves en lycée).<br/>
</p><div class="video-placeholder-container">
</div><p></p>
<p><small>5 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/mettre-en-lien-une-scene-3d-blender-et-une-interface-gtk-wxpython-grace-a-upbge/2477">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>phroy</name>
        </author>
    </entry>
    <entry>
        <title>V4L2 - Basculement de fréquence (PAL/NTSC)</title>
        <link href="https://linuxfr.org/forums/linux-general/posts/v4l2-basculement-de-frequence-pal-ntsc" />
        <id>https://linuxfr.org/forums/linux-general/posts/v4l2-basculement-de-frequence-pal-ntsc</id>
        <updated>2025-02-17T13:06:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Je rencontre une difficulté concernant la capture vidéo via une carte USB. En particulier, lorsque je dois basculer la source entre PAL et NTSC, cela provoque un freeze de la carte. En interrogeant la carte avec v4l2-ctl, je constate que la fréquence et la résolution ne se mettent pas à jour correctement.</p>
<p>La seule solution que j'ai trouvée pour forcer la mise à jour est d'utiliser usbreset pour redémarrer la carte, mais cela présente plusieurs inconvénients :</p>
<ul>
<li>Temps d'attente long : Le redémarrage de la carte est relativement lent.</li>
<li>Changement de chemin : Dans certains cas, après un redémarrage avec usbreset, le chemin de la carte peut changer, rendant l'accès compliqué.</li>
</ul>
<p>L’objectif est donc de pouvoir redémarrer ou rafraîchir la carte rapidement après un basculement de fréquence, mais je fais face à un comportement imprévisible :</p>
<p>Lorsque je capture avec ffmpeg, un changement de fréquence génère souvent une erreur, entraînant l'arrêt du programme. Cependant, parfois l'enregistrement continue malgré une image figée ou noire, ce qui rend la situation encore plus complexe à gérer et m'oblige à surveiller en permanence la fréquence pour relancer ffmpeg. </p>
<p>Je cherche un moyen plus propre et plus rapide de redémarrer la carte sans avoir recours à usbreset. Idéalement, le processus devrait être plus réactif, car actuellement, après un redémarrage via usbreset, il faut de temps en temps attendre au moins cinq secondes avant que la carte soit réutilisable. De plus, il arrive que l'utilisation de usbreset donne un message d’erreur "no such device", alors que v4l2-ctl retourne les bonnes informations.</p>
<p>Mon idée est de détecter quand ffmpeg s'arrête, quelle qu'en soit la cause, puis utiliser usbreset pour redémarrer la carte et relancer l'enregistrement. Mais je cherche une alternative plus rapide et fiable que l’utilisation de usbreset, tout en minimisant les risques de changement du chemin de la carte.</p>
<p>Y a-t-il une méthode plus propre et plus rapide pour redémarrer ou rafraîchir la carte vidéo via du code Python ou C ? Existe-t-il une API ou une commande qui pourrait résoudre ce problème sans avoir besoin de redémarrer complètement la carte ?</p>
<p>Merci pour toute aide ou suggestion que vous pourrez fournir.</p>
<div><a href="https://linuxfr.org/forums/linux-general/posts/v4l2-basculement-de-frequence-pal-ntsc.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138299/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-general/posts/v4l2-basculement-de-frequence-pal-ntsc#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>shingo</name>
        </author>
    </entry>
    <entry>
        <title>Cherche stage étudiant dev Python cet été - 1 mois</title>
        <link href="https://discuss.afpy.org/t/cherche-stage-etudiant-dev-python-cet-ete-1-mois/2476" />
        <id>https://discuss.afpy.org/t/cherche-stage-etudiant-dev-python-cet-ete-1-mois/2476</id>
        <updated>2025-02-15T10:09:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Mon fils est à la recherche d’un stage de dev en Python d’un mois cet été sur Paris. Pas forcément un dieu en programmation actuellement mais il a la volonté d’apprendre et il est par ailleurs très fort en maths (élève au lycée Louis Le Grand), ce qui peut aider pour certains types de projets.<br/>
Toutes les propositions sont les bienvenues.<br/>
cordialement,<br/>
JF</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/cherche-stage-etudiant-dev-python-cet-ete-1-mois/2476">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>jfhoup</name>
        </author>
    </entry>
    <entry>
        <title>Conda et le piège de la licence Anaconda</title>
        <link href="https://linuxfr.org/users/oumph/liens/conda-et-le-piege-de-la-licence-anaconda" />
        <id>https://linuxfr.org/users/oumph/liens/conda-et-le-piege-de-la-licence-anaconda</id>
        <updated>2025-02-12T23:03:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://bioinfo-fr.net/conda-et-le-piege-de-la-licence-anaconda">https://bioinfo-fr.net/conda-et-le-piege-de-la-licence-anaconda</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138261/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/oumph/liens/conda-et-le-piege-de-la-licence-anaconda#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 13 février</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-13-fevrier/2469" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-13-fevrier/2469</id>
        <updated>2025-02-06T15:24:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>On se retrouve le jeudi 13 février à 19h où David nous parlera des difficultés rencontrées par les personnes qui débutent en Python !</p>
<p>Pour ce meetup, nous serons accueillis par OVHcloud (métro Garibaldi).</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-13-fevrier/2469/1">Père Castor 🐻, raconte-nous une histoire (de Python) 🐍</a></p>
<p>2025-02-13 19:00 (Europe/Paris) → 2025-02-13 21:30 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-13-fevrier/2469">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Migration Hackinscience → Genepy</title>
        <link href="https://discuss.afpy.org/t/migration-hackinscience-genepy/2467" />
        <id>https://discuss.afpy.org/t/migration-hackinscience-genepy/2467</id>
        <updated>2025-02-04T21:44:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Certains ont suivi de très près (le design est de Marie-Ange, qui a fait le design de la PyConFR 2023, l’intégration de <a class="mention" href="https://discuss.afpy.org/u/grewn0uille">@grewn0uille</a> et <a class="mention" href="https://discuss.afpy.org/u/lize">@liZe</a>), d’autres moins.</p>
<p>En tout cas ça y est la migration de <a href="https://hackinscience.org">https://hackinscience.org</a> vers <a href="https://genepy.org">https://genepy.org</a> est bien lancée !</p>
<p>Faites-moi remonter les bugs, je vois qu’il y a des gens (dans les logs), mais je ne vois pas trop si ça se passe bien pour eux <img alt=":smiley:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiley.png?v=12" title=":smiley:" width="20"/></p>
<p>J’ai crée :</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="16" src="https://static.piaille.fr/site_uploads/files/000/000/006/16/fcf69fc645b8b165.png" width="16"/>
<a href="https://piaille.fr/@genepy" rel="noopener" target="_blank">Piaille</a>
</header>
<article class="onebox-body">
<img class="thumbnail onebox-avatar" height="400" src="https://static.piaille.fr/accounts/avatars/113/526/673/096/294/597/original/4a35a7e90e0d1606.png" width="400"/>
<h3><a href="https://piaille.fr/@genepy" rel="noopener" target="_blank">Genepy.org (@genepy@piaille.fr)</a></h3>
<p>16 Messages, 0 Abonnements, 7 Abonné·e·s · Genepy (actuellement HackInScience) est un site d'apprentissage de #Python, libre et open-source, gratuit et sans pubs (enfin, normal, quoi).

Compte tenu par [Julien](@mdk@mamot.fr).</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>je vais essayer d’y publier un peu la progression du projet.</p>
<p>Et ça serait cool de faire remonter l’équipe AFPy en 1ère place <img alt=":smiley:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/smiley.png?v=12" title=":smiley:" width="20"/></p>
<p><small>23 messages - 9 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/migration-hackinscience-genepy/2467">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Première publication libre de Multigit</title>
        <link href="https://linuxfr.org/news/premiere-publication-libre-de-multigit" />
        <id>https://linuxfr.org/news/premiere-publication-libre-de-multigit</id>
        <updated>2025-02-03T06:06:39Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <div><p>Multigit est un outil graphique conçu pour simplifier la gestion de projets composés de beaucoup de dépôts git. </p>
<p>Une image et une vidéo valant mieux qu'un long discours, voici à quoi ça ressemble:</p>
<p><img alt="Screenshot" src="https://img.linuxfr.org/img/68747470733a2f2f707269766174652d757365722d696d616765732e67697468756275736572636f6e74656e742e636f6d2f3133323433313733342f3430383831373737392d64316533316433372d323634392d343966652d383033302d3766626531366330643065642e706e673f6a77743d65794a68624763694f694a49557a49314e694973496e523563434936496b705856434a392e65794a7063334d694f694a6e6158526f6457497559323974496977695958566b496a6f69636d46334c6d647064476831596e567a5a584a6a623235305a5735304c6d4e7662534973496d746c65534936496d746c655455694c434a6c654841694f6a45334d7a67304d7a4d354f446373496d35695a6949364d54637a4f44517a4d7a59344e7977696347463061434936496938784d7a49304d7a45334d7a51764e4441344f4445334e7a63354c5751785a544d785a444d334c5449324e446b744e446c6d5a5330344d444d774c54646d596d55784e6d4d775a44426c5a433577626d635f5743314262586f745157786e62334a706447687450554658557a51745345314251793154534545794e54596d5743314262586f7451334a6c5a47567564476c686244314253306c42566b4e5052466c4d553045314d314252537a526151535579526a49774d6a55774d6a41784a544a4764584d745a57467a644330784a544a47637a4d6c4d6b5a6864334d3058334a6c6358566c6333516d5743314262586f74524746305a5430794d4449314d4449774d5651784f4445304e4464614a6c6774515731364c55563463476c795a584d394d7a41774a6c6774515731364c564e705a323568644856795a5430784d44426c4d7a4579596d4d31595459325a446b334f4455315932526b4d7a457a4f44637a4d7a4e6a4e4749774d6d45304d6a46694e546b354d4455325a5449774d6a42694d6a4a694d4441334e4463784f54566d4a6c6774515731364c564e705a32356c5a45686c5957526c636e4d396147397a64434a392e6d6f58614c5f4a4f5530565166446438733630694f7a6369736f566e6352626e6d68527750517932633051/408817779-d1e31d37-2649-49fe-8030-7fbe16c0d0ed.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg0MzM5ODcsIm5iZiI6MTczODQzMzY4NywicGF0aCI6Ii8xMzI0MzE3MzQvNDA4ODE3Nzc5LWQxZTMxZDM3LTI2NDktNDlmZS04MDMwLTdmYmUxNmMwZDBlZC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwMjAxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDIwMVQxODE0NDdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0xMDBlMzEyYmM1YTY2ZDk3ODU1Y2RkMzEzODczMzNjNGIwMmE0MjFiNTk5MDU2ZTIwMjBiMjJiMDA3NDcxOTVmJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.moXaL_JOU0VQfDd8s60iOzcisoVncRbnmhRwPQy2c0Q" title="Source : https://private-user-images.githubusercontent.com/132431734/408817779-d1e31d37-2649-49fe-8030-7fbe16c0d0ed.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg0MzM5ODcsIm5iZiI6MTczODQzMzY4NywicGF0aCI6Ii8xMzI0MzE3MzQvNDA4ODE3Nzc5LWQxZTMxZDM3LTI2NDktNDlmZS04MDMwLTdmYmUxNmMwZDBlZC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwMjAxJTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDIwMVQxODE0NDdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT0xMDBlMzEyYmM1YTY2ZDk3ODU1Y2RkMzEzODczMzNjNGIwMmE0MjFiNTk5MDU2ZTIwMjBiMjJiMDA3NDcxOTVmJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.moXaL_JOU0VQfDd8s60iOzcisoVncRbnmhRwPQy2c0Q"/></p>
</div><ul><li>lien nᵒ 1 : <a href="https://linuxfr.org/redirect/115134" hreflang="en" title="https://github.com/user-attachments/assets/42327500-bc9d-4b52-82fd-b7dc85aff145">Vidéo de l'utilisation de Multigit</a></li><li>lien nᵒ 2 : <a href="https://linuxfr.org/redirect/115135" hreflang="en" title="https://github.com/idemia/multigit">Dépôt Github</a></li><li>lien nᵒ 3 : <a href="https://linuxfr.org/redirect/115136" hreflang="en" title="https://github.com/idemia/multigit/releases/tag/MULTIGIT_OPENSOURCE_v1.6.1">Téléchargement de la version 1.6.1</a></li></ul><div><p>Je l'ai développé dans le cadre de mon travail chez IDEMIA où nous sommes souvent confrontés à plus de trente (voire plus de soixante) dépôts à gérer conjointement sur un projet. Dans ce contexte, la moindre opération git devient un mini-défi qu'il fallait relever quotidiennement.</p>
<p>Multigit est abouti et stable, il est utilisé au quotidien par plus d'une centaine de personnes (sous Windows), depuis plusieurs années. Mon employeur m'a aimablement autorisé à le publier en Open Source, ce dont je lui sais gré. Il est publié sous licence Apache 2.0 </p>
<p>La problématique de gestion de plusieurs dépôts git conjoints pour un projet est assez peu répandue dans le monde du logiciel libre. Mais beaucoup plus dans le monde de l'entreprise. En effet, git ne gère pas la notion de droit d'accès à une partie d'un dépôt. La seule façon de restreindre l'accès à certains parties d'un projet est donc de créer un dépôt spécifique pour les y stocker, avec des droits d'accès au niveau du dépôt. Ajoutons à cela beaucoup de personnes, beaucoup de projets parfois complexes, beaucoup de sous-projets, beaucoup d'historique et on se retrouve avec une gestion des sources particulièrement complexe. Complexe … avant l'arrivée de <em>Multigit</em> en tout cas.</p>
<p><strong>Installation</strong></p>
<p>Sous Linux, la seule option d'installation disponible à l'heure actuelle est Python + pip, ou encore mieux avec pipx:</p>
<pre><code>    $ sudo apt install python-pipx
    $ pipx install multigit_gx
    $ multigit
</code></pre>
<p>Sous Windows, un installeur graphique click-and-play vous permettra d'arriver au même résultat.</p>
<p>J'ai bien tenté de fournir un <em>snap</em> pour Linux mais snap est conçu pour empêcher à peu près tout ce que veut faire Multigit: accèder à tous vos fichiers et lancer des programmes de votre distribution (git, gitk, …)</p>
<p>Je ferai mieux dans la prochaine version. D'ailleurs, si vous avez des recommandations pour un packaging moderne, simple, facile à maintenir et couvrant toutes les distributions Linux, je suis preneur.</p>
<p><strong>Contribution</strong></p>
<p>Le projet est géré sous <a href="https://github.com/idemia/multigit">GitHub</a>, les contributions ou les retours sont les bienvenus.</p>
</div><div><a href="https://linuxfr.org/news/premiere-publication-libre-de-multigit.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138132/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/premiere-publication-libre-de-multigit#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Philippe F,bobble bubble,Benoît Sibaud</name>
        </author>
    </entry>
    <entry>
        <title>Demande pour que mon code python aille 1 million de fois plus vite car j&#39;ai au moins 4 millions de f</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/demande-pour-que-mon-code-python-aille-1-million-de-fois-plus-vite-car-j-ai-au-moins-4-millions-de-f" />
        <id>https://linuxfr.org/forums/programmation-python/posts/demande-pour-que-mon-code-python-aille-1-million-de-fois-plus-vite-car-j-ai-au-moins-4-millions-de-f</id>
        <updated>2025-02-03T02:09:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
j'aurais besoin d'aide pour que le code ci-dessous aille beaucoup beaucoup plus vite, car j'ai plus de 4 millions de fichier à exécuter avec ce code et si je le laisse tel qu'il est j'en aurais pour au moins une à 2 semaines d'exécution. Alors que je dois l'utiliser toutes les semaines. Le code fais une recherchev par rapport à mon 1er tableau et met les valeurs dans mes fichiers, fais la somme de ma recherchev, supprime les valeurs de ma recherchev et place la ligne ou il y a la somme où il doit être placé.<br/>
Ensuite il fait la même chose pour un 2ème tableau et idem pour un 3ème tableau, et pour un 4ème tableau, ça va jusqu'à 10 tableau.<br/>
S'il vous plaît, c'est complexe pour moi donc si vous pouvez m'aider. Voici le code:<br/>
import os</p>
<p>|| || || |import pandas as pd| |from openpyxl import load_workbook| || |# ???? Définition des chemins| |dossier_source = "D:/PYTHON/VALEUR REMPLACER ZIP"| |fichier_rebase = "D:/PYTHON/REBASE.xlsx"| || |# ???? Chargement des valeurs de REBASE.xlsx| |wb_rebase = load_workbook(fichier_rebase, data_only=True)| |ws_rebase = wb_rebase.active| || |# ???? Extraction des valeurs des <strong>Tableaux 1 (A:B), 2 (D:E), 3 (G:H) et 4 (J:K)</strong>| |tableau_1 = pd.DataFrame(ws_rebase.iter_rows(min_row=1, max_row=273, min_col=1, max_col=2, values_only=True), columns=["Clé", "Valeur"])| |tableau_2 = pd.DataFrame(ws_rebase.iter_rows(min_row=1, max_row=273, min_col=4, max_col=5, values_only=True), columns=["Clé", "Valeur"])| |tableau_3 = pd.DataFrame(ws_rebase.iter_rows(min_row=1, max_row=273, min_col=7, max_col=8, values_only=True), columns=["Clé", "Valeur"])| |tableau_4 = pd.DataFrame(ws_rebase.iter_rows(min_row=1, max_row=273, min_col=10, max_col=11, values_only=True), columns=["Clé", "Valeur"])| || |# ???? Traitement des fichiers dans le dossier source| |for fichier in os.listdir(dossier_source):| |if fichier.endswith(".xlsx"):| |chemin_fichier = os.path.join(dossier_source, fichier)| || |# ???? Charger le fichier Excel| |wb = load_workbook(chemin_fichier)| |ws = wb.active| || |# ???? Identifier la dernière ligne contenant des données (entre 1 et 19)| |last_data_row = max([i for i in range(1, 20) if any(ws.cell(row=i, column=j).value for j in range(2, ws.max_column + 1))], default=1)| || |### ✅ Étape 1 : Remplacement avec le <strong>Tableau 1 (A:B)</strong>| |ligne_depart = 21| |if any(ws.cell(row=21, column=j).value for j in range(2, ws.max_column + 1)):| |ligne_depart = max([i for i in range(21, ws.max_row + 1) if any(ws.cell(row=i, column=j).value for j in range(2, ws.max_column + 1))], default=20) + 2 | || |ligne_debut_bloc_1 = ligne_depart| || |# ???? <strong>Ajout des valeurs du Tableau 1</strong>| |for col in range(2, ws.max_column + 1):| |for row in range(1, last_data_row + 1):| |valeur_originale = ws.cell(row=row, column=col).value| |if valeur_originale:| |valeur_remplacee = tableau_1.loc[tableau_1["Clé"] == valeur_originale, "Valeur"]| |if not valeur_remplacee.empty:| |ws.cell(row=ligne_depart + row - 1, column=col, value=valeur_remplacee.values[0])| || |# ???? Calcul de la somme du <strong>Tableau 1</strong>| |ligne_somme_1 = ligne_depart + last_data_row + 1| |somme_bloc_1 = [sum(ws.cell(row=row, column=col).value or 0 for row in range(ligne_debut_bloc_1, ligne_somme_1) if isinstance(ws.cell(row=row, column=col).value, (int, float))) for col in range(2, ws.max_column + 1)]| || |# ???? <strong>Suppression du bloc 1 et insertion des sommes à la ligne 21</strong>| |for row in range(ligne_debut_bloc_1, ligne_somme_1):| |for col in range(2, ws.max_column + 1):| |ws.cell(row=row, column=col, value=None)| |ws.delete_rows(ligne_debut_bloc_1, ligne_somme_1 - ligne_debut_bloc_1)| |ws.insert_rows(21)| |for col_idx, somme in enumerate(somme_bloc_1, start=2):| |ws.cell(row=21, column=col_idx, value=somme)| || |### ✅ Étape 4 : Remplacement avec le <strong>Tableau 4 (J:K)</strong>| |ligne_depart = max([i for i in range(21, ws.max_row + 1) if any(ws.cell(row=i, column=j).value for j in range(2, ws.max_column + 1))], default=20) + 2 | |ligne_debut_bloc_4 = ligne_depart| || |# ???? <strong>Ajout des valeurs du Tableau 4</strong>| |for col in range(2, ws.max_column + 1):| |for row in range(1, last_data_row + 1):| |valeur_originale = ws.cell(row=row, column=col).value| |if valeur_originale:| |valeur_remplacee = tableau_4.loc[tableau_4["Clé"] == valeur_originale, "Valeur"]| |if not valeur_remplacee.empty:| |ws.cell(row=ligne_depart + row - 1, column=col, value=valeur_remplacee.values[0])| || |# ???? Calcul de la somme du <strong>Tableau 4</strong>| |ligne_somme_4 = ligne_depart + last_data_row + 1| |somme_bloc_4 = [sum(ws.cell(row=row, column=col).value or 0 for row in range(ligne_debut_bloc_4, ligne_somme_4) if isinstance(ws.cell(row=row, column=col).value, (int, float))) for col in range(2, ws.max_column + 1)]| || |# ???? <strong>Suppression du bloc 4 et insertion des sommes à la ligne 24</strong>| |for row in range(ligne_debut_bloc_4, ligne_somme_4):| |for col in range(2, ws.max_column + 1):| |ws.cell(row=row, column=col, value=None)| |ws.delete_rows(ligne_debut_bloc_4, ligne_somme_4 - ligne_debut_bloc_4)| |ws.insert_rows(24)| |for col_idx, somme in enumerate(somme_bloc_4, start=2):| |ws.cell(row=24, column=col_idx, value=somme)| || |wb.save(chemin_fichier)| |print(f"✅ {fichier} mis à jour avec succès.")| || |print("✔ Tous les fichiers ont été traités correctement.")|</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/demande-pour-que-mon-code-python-aille-1-million-de-fois-plus-vite-car-j-ai-au-moins-4-millions-de-f.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138148/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/demande-pour-que-mon-code-python-aille-1-million-de-fois-plus-vite-car-j-ai-au-moins-4-millions-de-f#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Lilie3887</name>
        </author>
    </entry>
    <entry>
        <title>Inline C dans une fonction Python</title>
        <link href="https://discuss.afpy.org/t/inline-c-dans-une-fonction-python/2463" />
        <id>https://discuss.afpy.org/t/inline-c-dans-une-fonction-python/2463</id>
        <updated>2025-02-01T21:45:19Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Parce que, je voulais voir où ça mènerai, bah ça mène là (pour Linux uniquement) :</p>
<pre><code class="lang-python">import shlex
import tempfile
from ctypes import CDLL, py_object
from functools import wraps
from inspect import signature
from subprocess import PIPE, run


def compile(c_str) -&gt; CDLL:
    with tempfile.TemporaryDirectory() as tmpdir:
        with open(f"{tmpdir}/tmp.c", "w", encoding="UTF-8") as f:
            f.write(c_str)
        flags = shlex.split(run(["python3-config", "--cflags", "--ldflags"], encoding="UTF-8", stdout=PIPE).stdout)
        run(["cc", "-shared", "-fPIC", "-xc"] + flags + [f"-o{tmpdir}/tmp.so", f"{tmpdir}/tmp.c"], check=True)
        return CDLL(f"{tmpdir}/tmp.so")


def c(fct):
    parameters = signature(fct).parameters
    c_args = ", ".join([f"PyObject *{name}" for name in parameters.keys()])
    lib = compile(FR"""
#include &lt;stdio.h&gt;
#include &lt;Python.h&gt;

PyObject *the_function({c_args}) {{
    {fct.__doc__}
}}
""")
    lib.the_function.argtypes = [py_object] * len(parameters)
    lib.the_function.restype = py_object
    @wraps(fct)
    def call_c(*args):
        return lib.the_function(*args)
    return call_c


@c
def cprint(pyobject):
    r"""
    Py_ssize_t size;
    const char *str;

    PyGILState_STATE state = PyGILState_Ensure();
    if (PyUnicode_CheckExact(pyobject)) {
        str = PyUnicode_AsUTF8AndSize(pyobject, &amp;size);
        write(1, str, size);
        write(1, "\n", 1);
    }
    else {
        PyObject *repr = PyObject_Repr(pyobject);
        printf("%s\n", PyUnicode_AsUTF8(repr));
    }
    PyGILState_Release(state);
    return Py_None;
    """


@c
def fib(n):
    """
    long m = PyLong_AsLong(n);
    long a = 1;
    long b = 1;

    PyGILState_STATE state = PyGILState_Ensure();
    for (int i = 0; i &lt; m; i++) {
        b = a + b;
        a = b - a;
    }
    n = PyLong_FromLong(a);
    PyGILState_Release(state);
    return n;
    """


def main():
    cprint([fib(i) for i in range(40)])


if __name__ == "__main__":
    main()
</code></pre>
<p>Bon ça marche, ça m’amuse, c’est tout.</p>
<p>OK pour ceux qui veulent vraiment parler perfs, même si c’était pas mon but (promis) :</p>
<pre><code class="lang-python">$ pyperf timeit -s 'import inline_c' 'inline_c.py_fib(40)'
.....................
Mean +- std dev: 993 ns +- 70 ns

$ pyperf timeit -s 'import inline_c' 'inline_c.c_fib(40)'
.....................
Mean +- std dev: 257 ns +- 6 ns
</code></pre>
<p>mais on perd la magie des <code>int</code> de Python, très vite le <code>long</code> ne suffira pas a contenir le résultat de fib, les deux implèms ne sont donc pas comparables, l’une est rapide, l’autre est juste, meh, arrêtons de parler perfs.</p>
<p>Qui pour implémenter <code>@asm</code> ?</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/inline-c-dans-une-fonction-python/2463">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Envie de contribuer à Python</title>
        <link href="https://discuss.afpy.org/t/envie-de-contribuer-a-python/2461" />
        <id>https://discuss.afpy.org/t/envie-de-contribuer-a-python/2461</id>
        <updated>2025-02-01T13:56:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello les pythonistes !</p>
<p>J’ai envie de contribuer à Python à mon niveau, mais en allant sur le github, je suis un peu perdue pour trouver par où commencer, sachant que je ne connais pas du tout C.</p>
<p>Est-ce que vous auriez des conseils ?</p>
<p>Merci</p>
<p><small>7 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/envie-de-contribuer-a-python/2461">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Karine</name>
        </author>
    </entry>
    <entry>
        <title>Simplifier l’accès aux données météo</title>
        <link href="https://linuxfr.org/users/zilkos/liens/simplifier-l-acces-aux-donnees-meteo" />
        <id>https://linuxfr.org/users/zilkos/liens/simplifier-l-acces-aux-donnees-meteo</id>
        <updated>2025-01-31T09:49:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://medium.com/oss-by-maif/meteole-simplifier-lacc%C3%A8s-aux-donn%C3%A9es-m%C3%A9t%C3%A9o-afeec5e5d395">https://medium.com/oss-by-maif/meteole-simplifier-lacc%C3%A8s-aux-donn%C3%A9es-m%C3%A9t%C3%A9o-afeec5e5d395</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138122/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/zilkos/liens/simplifier-l-acces-aux-donnees-meteo#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Pwayt</name>
        </author>
    </entry>
    <entry>
        <title>wrapper python pour une lib en C</title>
        <link href="https://discuss.afpy.org/t/wrapper-python-pour-une-lib-en-c/2460" />
        <id>https://discuss.afpy.org/t/wrapper-python-pour-une-lib-en-c/2460</id>
        <updated>2025-01-31T06:18:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour ici,</p>
<p>j’ai un petit souci avec une lib en C que j’ai produite avec une seule fonction.</p>
<p>Le code C de <em>toto.c</em> :</p>
<pre><code class="lang-python">#include &lt;stdio.h&gt;

char * titi(void) {
	return "Hello world!";
}
</code></pre>
<p>qui donne <em>toto.so</em>.</p>
<p>Le wrapper python <em>toto.py</em> :</p>
<pre><code class="lang-python">from ctypes import CDLL, c_char_p

# Load the shared library
toto = CDLL("./toto.so")
toto.titi.restype = c_char_p
</code></pre>
<p>Et le code de test <em>test_toto.py</em> :</p>
<pre><code class="lang-python">import toto

print(toto.titi())
</code></pre>
<p>Voilà, un truc assez basique, j’ai jeté un oeil à pas mal de tutos, et j’obtiens toujours la même erreur quand j’utilise le dernier script :</p>
<pre><code class="lang-python">Traceback (most recent call last):
  File "test_toto.py", line 1, in &lt;module&gt;
    import toto
ImportError: dynamic module does not define module export function (PyInit_toto)
</code></pre>
<p>Si j’exécute la fonction titi depuis le fichier <em>toto.py</em>, elle est bien appelée sans souci. Mais il semble que je ne puisse pas l’appeler depuis un import.</p>
<p>Sur les internets ça parle de version de compilateur,… Si vous avez une idée, je suis preneur !</p>
<p><small>4 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/wrapper-python-pour-une-lib-en-c/2460">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Mindiell</name>
        </author>
    </entry>
    <entry>
        <title>Bonne année 2025 !</title>
        <link href="https://discuss.afpy.org/t/bonne-annee-2025/2458" />
        <id>https://discuss.afpy.org/t/bonne-annee-2025/2458</id>
        <updated>2025-01-30T17:01:56Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour tout le monde,</p>
<p>L’AFPy vous souhaite une bonne année 2025 et vous présente ses meilleurs vœux pour cette nouvelle année !</p>
<p>En ce début d’année, nous avons lancé notre campagne d’adhésions 2025 sur HelloAsso : <a href="https://www.helloasso.com/associations/afpy/adhesions/adhesion-2025-a-l-afpy">https://www.helloasso.com/associations/afpy/adhesions/adhesion-2025-a-l-afpy</a> <img alt=":sparkles:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/sparkles.png?v=12" title=":sparkles:" width="20"/></p>
<p>Être membre de l’AFPy vous permet de prendre part à la vie de l’association en votant lors de l’Assemblée Générale et vous permettez à l’APFy de financer ses frais de fonctionnement, d’engager les dépenses pour l’organisation de la PyConFR et d’assurer la promotion du langage Python en francophonie <img alt=":snake:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/snake.png?v=12" title=":snake:" width="20"/></p>
<p>Concernant les vidéos de la PyConFR 2024, une bonne partie est disponible sur IndyMotion : <a href="https://indymotion.fr/c/pyconfr2024/">PyConFR2024 - IndyMotion</a><br/>
D’autres nécessitent plus de travail et sont encore en cours de traitement. Elles arriveront au fur et à mesure !</p>
<p>Pour ne manquer aucune nouvelle sur l’AFPy, les meetups locaux et la PyConFR, vous pouvez nous suivre sur nos différents réseaux (<a class="inline-onebox" href="https://mamot.fr/@AFPy">AFPy (@AFPy@mamot.fr) - Mamot - Le Mastodon de La Quadrature du Net</a> et  <a class="inline-onebox" href="https://www.linkedin.com/company/afpy">Association Francophone Python (AFPy) | LinkedIn</a>), participer sur le forum (<a href="https://discuss.afpy.org/">https://discuss.afpy.org/</a>) ou le salon Discord (<a href="https://www.afpy.org/discord">AFPy</a>) <img alt=":blush:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/blush.png?v=12" title=":blush:" width="20"/></p>
<p>Merci pour votre soutien <img alt=":sparkling_heart:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/sparkling_heart.png?v=12" title=":sparkling_heart:" width="20"/></p>
<p>–<br/>
L’équipe de l’AFPy (Association Francophone Python)</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/bonne-annee-2025/2458">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Bras robotisé MKX3D</title>
        <link href="https://discuss.afpy.org/t/bras-robotise-mkx3d/2457" />
        <id>https://discuss.afpy.org/t/bras-robotise-mkx3d/2457</id>
        <updated>2025-01-29T17:13:18Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous, je vous présente le <strong>bras robotisé MKX3D</strong> open source.</p>
<ul>
<li>Il est <strong>réellement open source</strong> en effet les fichiers CAO (SolidWorks) sont sous CC BY-NC-SA et l’interface de prog en GNU GPL.</li>
<li>Il est programmable en <strong>Python</strong>.</li>
<li>Le bras est <strong>complétement imprimable</strong> son coût est autour des 400 € (l’équivalent dans le commerce est à 4000 € et bien évidement en closed)</li>
<li>La plateforme de dev est <strong>Blender/UPBGE + Python + Arduino</strong></li>
</ul>
<p>Le dépôt est sur <strong>la Forge</strong> (gitlab de l’Education Nationale) : <a class="inline-onebox" href="https://forge.apps.education.fr/bras-mkx3d/jumeau-numerique" rel="noopener nofollow ugc">Bras MKX3D / Jumeau numérique · GitLab</a></p>
<p>Une présentation plus longue (20 min) est ici : <a class="inline-onebox" href="https://tube-sciences-technologies.apps.education.fr/w/68DoiGYuMfRK8JcFKVSors" rel="noopener nofollow ugc">Bras MKX3D : Présentation longue - Sciences &amp; Technologies</a></p>
<p></p><div class="video-placeholder-container">
</div><p></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/bras-robotise-mkx3d/2457">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>phroy</name>
        </author>
    </entry>
    <entry>
        <title>Comment maîtriser sa dette technique</title>
        <link href="https://bearstech.com/societe/blog/comment-maitriser-sa-dette-technique" />
        <id>https://bearstech.com/societe/blog/comment-maitriser-sa-dette-technique</id>
        <updated>2025-01-28T13:04:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>Sur Aix-en-Provence − Meetup le 6 février</title>
        <link href="https://discuss.afpy.org/t/sur-aix-en-provence-meetup-le-6-fevrier/2455" />
        <id>https://discuss.afpy.org/t/sur-aix-en-provence-meetup-le-6-fevrier/2455</id>
        <updated>2025-01-28T11:10:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Il y a un meetup Python sur Aix-en-Provence le jeudi 6 février.<br/>
Rendez-vous à partir de 18h à « Chez les Copains ».</p>
<p>Organisé par Karine (Karine sur Discord :)).</p>
<p>N’hésitez pas à signaler votre présence sur le thread “Meetup à Aix-en-Provence” sur Discord afin de faciliter la réservation !</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-aix-en-provence-meetup-le-6-fevrier/2455/1">Meetup Aix-en-Provence</a></p>
<p>2025-02-06 18:00 (Europe/Paris) → 2025-02-06 22:00 (Europe/Paris)</p>
</div>
<p><small>5 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-aix-en-provence-meetup-le-6-fevrier/2455">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>activation (rond noirci) d&#39;un radiobouton + thread ?</title>
        <link href="https://discuss.afpy.org/t/activation-rond-noirci-dun-radiobouton-thread/2454" />
        <id>https://discuss.afpy.org/t/activation-rond-noirci-dun-radiobouton-thread/2454</id>
        <updated>2025-01-26T16:25:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
je veux lancer des programmes à l’aide de radiobouton. Dans le cas d’un flatpak, il faut un certain temps pour l’ouvrir. Dans ce cas le radiobouton ne s’active qu’après la fermeture du flatpak correctement lancé. J’ai pensé que c’était une histoire de thread mais je n’y arrive visiblement pas. Un petit coup de main serait le bienvenu.</p>
<pre><code class="lang-python">def task():
	if var.get() == 1:
		var.set(1)
	elif var.get() == 2:
		var.set(2)

def run_app():
	if var.get() == 1:
		wr_ge='flatpak run org.gimp.GIMP'
		subprocess.run(wr_ge, shell=True)
	elif var.get() == 2:
		subprocess.Popen('/usr/bin/pdfarranger')

fen = Tk()
fen.geometry('350x100+1200+300')
var = IntVar()
c1 = Radiobutton(fen, text='GIMP : éditeur graphique',variable=var, bg="bisque", command=run_app, value = 1)
c1.place(x=10,y=10)
c2 = Radiobutton(fen, text='PDFarranger : gestionnaire PDF',variable=var, bg="bisque", command=run_app, value = 2)
c2.place(x=10,y=40)
t1 = Thread(target=task)
t1.start()
fen.mainloop()
t1.join()
</code></pre>
<p><small>6 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/activation-rond-noirci-dun-radiobouton-thread/2454">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Un usage utile du sys.meta_path en Python</title>
        <link href="https://zestedesavoir.com/billets/4815/un-usage-utile-du-sys-meta-path-en-python/" />
        <id>https://zestedesavoir.com/billets/4815/un-usage-utile-du-sys-meta-path-en-python/</id>
        <updated>2025-01-23T22:59:19Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Installation de modules</title>
        <link href="https://discuss.afpy.org/t/installation-de-modules/2450" />
        <id>https://discuss.afpy.org/t/installation-de-modules/2450</id>
        <updated>2025-01-23T11:37:36Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Comment installer simplement des paquets ?</p>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/installation-de-modules/2450">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Pierre</name>
        </author>
    </entry>
    <entry>
        <title>EuroPython - Calls for Proposals Closes Soon</title>
        <link href="https://discuss.afpy.org/t/europython-calls-for-proposals-closes-soon/2448" />
        <id>https://discuss.afpy.org/t/europython-calls-for-proposals-closes-soon/2448</id>
        <updated>2025-01-21T11:47:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello everyone!</p>
<p>We’re excited to share that EuroPython is returning to Prague in 2025! It’s a week of all things Python—tutorials, talks, sprints, an unconference space, social events, networking, and plenty of fun.</p>
<p>The Call for Proposals closes on January 27th at 23:59 UTC, so be sure to send yours in before the deadline. You can find all the details here: <a class="inline-onebox" href="https://ep2025.europython.eu/programme/cfp/" rel="noopener nofollow ugc">Call for Proposals | EuroPython 2025 | July 14th-20th 2025 | Prague, Czech Republic &amp; Remote</a>.</p>
<p>We’d also love to hear your thoughts on EuroPython! What would you like to see this year? Share your opinion in this short planning survey: <a href="https://forms.gle/JqG9Pks5KxDsxToi9" rel="noopener nofollow ugc">https://forms.gle/JqG9Pks5KxDsxToi9</a>.</p>
<p>We can’t wait to see you at EuroPython!</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/europython-calls-for-proposals-closes-soon/2448">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>clytaemnestra</name>
        </author>
    </entry>
    <entry>
        <title>[POC] Microcontrôleurs et prototypage facile en Python (et Blockly)</title>
        <link href="https://linuxfr.org/users/epeios/liens/poc-microcontroleurs-et-prototypage-facile-en-python-et-blockly" />
        <id>https://linuxfr.org/users/epeios/liens/poc-microcontroleurs-et-prototypage-facile-en-python-et-blockly</id>
        <updated>2025-01-20T15:57:24Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://zelbinium.q37.info/fr/ucuq/">https://zelbinium.q37.info/fr/ucuq/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/138006/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/epeios/liens/poc-microcontroleurs-et-prototypage-facile-en-python-et-blockly#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Claude SIMON</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 29 janvier</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-29-janvier/2445" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-29-janvier/2445</id>
        <updated>2025-01-20T10:57:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde !</p>
<p>Pour ce premier meetup de 2025 à Lyon, on se retrouve le mercredi 29 janvier dans les locaux de Malt (Bellecour) à 19h.</p>
<p>Carmen nous parlera d’optimisation des requêtes SQL dans Django et SQLAlchemy.</p>
<p>Pour les personnes que ça intéresse, les meetup Python ont maintenant leur compte Mastodon : <a class="inline-onebox" href="https://piaille.fr/@python_lyon">Python Lyon (@python_lyon@piaille.fr) - Piaille</a>.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-29-janvier/2445/1">Optimisation des requêtes SQL dans Django et SQLAlchemy : le problème N+1</a></p>
<p>2025-01-29 19:00 (Europe/Paris) → 2025-01-29 21:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-29-janvier/2445">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Linux Mint : améliorer votre terminal ZSH avec l’auto-suggestion et la coloration syntaxique</title>
        <link href="https://www.olivierpons.fr/2025/01/20/linux-mint-ameliorer-votre-terminal-zsh-avec-lauto-suggestion-et-la-coloration-syntaxique/" />
        <id>https://www.olivierpons.fr/2025/01/20/linux-mint-ameliorer-votre-terminal-zsh-avec-lauto-suggestion-et-la-coloration-syntaxique/</id>
        <updated>2025-01-20T07:47:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Comment améliorer votre terminal ZSH avec l’auto-suggestion et la coloration syntaxique</h1>
<p>Vous utilisez ZSH comme shell par défaut mais vous souhaitez le rendre plus puissant et agréable à utiliser ? Dans cet article, nous allons voir comment installer et configurer deux plugins essentiels : zsh-autosuggestions pour l’auto-complétion intelligente et zsh-syntax-highlighting pour la coloration syntaxique en temps réel.</p>
<h2>Prérequis</h2>
<ul>
<li>ZSH installé comme shell par défaut</li>
<li>Git installé sur votre système</li>
<li>Droits d’accès à votre répertoire personnel</li>
</ul>
<h2>Installation des plugins</h2>
<p>Commençons par créer un dossier dédié pour nos plugins ZSH et clonons les dépôts nécessaires :</p>
<pre style="margin: 0; padding: 0; font-size: smaller;">mkdir -p ~/.zsh
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ~/.zsh/zsh-syntax-highlighting</pre>
<h2>Configuration</h2>
<h3>1. Activation des plugins</h3>
<p>Ajoutez ces lignes à votre fichier <code>~/.zshrc</code> pour activer les plugins :</p>
<pre><code>source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh</code></pre>
<h3>2. Mise à jour de la liste des plugins</h3>
<p>Si vous utilisez Oh My Zsh, modifiez la ligne des plugins dans votre fichier <code>~/.zshrc</code> :</p>
<pre><code>plugins=(git thefuck poetry zsh-autosuggestions zsh-syntax-highlighting)</code></pre>
<h2>Fonctionnalités</h2>
<h3>Auto-suggestions</h3>
<p>Le plugin zsh-autosuggestions vous suggère des commandes basées sur votre historique pendant que vous tapez. Pour accepter une suggestion, appuyez simplement sur la touche <img alt="➡" class="wp-smiley" src="https://s.w.org/images/core/emoji/17.0.2/72x72/27a1.png" style="height: 1em;"/> (flèche droite).</p>
<h3>Coloration syntaxique</h3>
<p>zsh-syntax-highlighting colore vos commandes en temps réel :</p>
<ul>
<li>Commandes valides en vert</li>
<li>Commandes invalides en rouge</li>
<li>Options et arguments en couleurs distinctes</li>
<li>Chemins de fichiers existants soulignés</li>
</ul>
<h2>Conclusion</h2>
<p>Avec ces deux plugins, votre terminal ZSH devient beaucoup plus convivial et efficace. L’auto-suggestion vous fait gagner du temps en proposant les commandes pertinentes, tandis que la coloration syntaxique vous aide à repérer rapidement les erreurs de frappe.</p>
<h3>Conseils bonus</h3>
<ul>
<li>Redémarrez votre terminal ou exécutez <code>source ~/.zshrc</code> pour appliquer les changements</li>
<li>Vous pouvez personnaliser les couleurs et le comportement des plugins en consultant leur documentation respective sur GitHub</li>
<li>Ces plugins sont compatibles avec la plupart des frameworks ZSH comme Oh My Zsh et Prezto</li>
</ul>
<p><em>N’hésitez pas à laisser un commentaire si vous rencontrez des difficultés ou si vous souhaitez partager d’autres astuces pour améliorer votre terminal !</em></p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Traducteur professionnel dispo</title>
        <link href="https://discuss.afpy.org/t/traducteur-professionnel-dispo/2443" />
        <id>https://discuss.afpy.org/t/traducteur-professionnel-dispo/2443</id>
        <updated>2025-01-19T13:00:03Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
La liste idoine est inacessible (“le site a mis trop de temps pour répondre”) donc je poste ici mon volontariat pour la trad de la doc, vu que j’ai commencé mon apprentissage et qu’il y a deux ou trois trucs à améliorer pour la doc en français. J’ai été le réviseur technique de mon épouse traductrice Anglais/Espagnol → Français pendant 24 ans, j’ai donc un peu d’expérience…<br/>
A+<br/>
Didier</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/traducteur-professionnel-dispo/2443">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>DMorandi</name>
        </author>
    </entry>
    <entry>
        <title>Les 10 commandements de l’éco-conception d’infrastructures chez Bearstech</title>
        <link href="https://bearstech.com/societe/blog/les-10-commandements-de-leco-conception-dinfrastructures-chez-bearstech" />
        <id>https://bearstech.com/societe/blog/les-10-commandements-de-leco-conception-dinfrastructures-chez-bearstech</id>
        <updated>2025-01-16T14:58:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>emazurier</name>
        </author>
    </entry>
    <entry>
        <title>SCAM ; publier un livre en organisant ses pensées</title>
        <link href="https://linuxfr.org/users/jul/journaux/scam-publier-un-livre-en-organisant-ses-pensees" />
        <id>https://linuxfr.org/users/jul/journaux/scam-publier-un-livre-en-organisant-ses-pensees</id>
        <updated>2025-01-14T10:18:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Alors que le résal social, c'est toute la rage voici une idée de concept « générons des livres depuis les discussions de réseaux sociaux ».</p>
<p>Bon, d'abord, c'est une preuve de concept qui se veut inspirée de l'institut LA RACHE basée sur le « Scope Creep Amusing Methodology »</p>
<p>Où l'on code librement dans la direction où l'on veut en s'en foutant des bonnes pratiques, et on regarde où ça nous mène <sup>_^</sup> (à bas la tyrannie de la PEP8, vive Perl, vive python)</p>
<p>Au début était une preuve de concept de dériver le modèle de donnée d'un formulaire HTML et d'en faire un CRUD (interface brut de manipulation de base de données depuis le web),</p>
<p>Puis ce fût un logiciel de microblogging (à la mode d'une tribune de linuxfr) pour illustrer comment utiliser HTML as a model,</p>
<p>Puis ce fût un organisateur d'idées (mind mapper).</p>
<p>Puis ce fût un logiciel d'édition de livres (chaîne pandoc basée sur du markdown avec rendu temps réel) fait à la va comme je te pousse basé sur un organigramme :D</p>
<p>Enfin, le manuel d'aide bâclé est lui même bricolé en 2h de temps avec l'outil pour prouver qu'on peut l'utiliser.</p>
<p>C'est en codant n'importe quoi, qu'on fait n'importe quoi.</p>
<p><a href="https://github.com/jul/scam">projet</a><br/>
<a href="https://raw.githubusercontent.com/jul/scam/main/assets/aide.book.pdf">manuel du projet fait avec le projet</a></p>
<div><a href="https://linuxfr.org/users/jul/journaux/scam-publier-un-livre-en-organisant-ses-pensees.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137947/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jul/journaux/scam-publier-un-livre-en-organisant-ses-pensees#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Jul</name>
        </author>
    </entry>
    <entry>
        <title>EuroPython 2025 − 14 au 20 juillet</title>
        <link href="https://discuss.afpy.org/t/europython-2025-14-au-20-juillet/2433" />
        <id>https://discuss.afpy.org/t/europython-2025-14-au-20-juillet/2433</id>
        <updated>2025-01-13T13:46:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>L’<a href="https://ep2025.europython.eu/">EuroPython</a> est de retour pour 2025 et a lieu du 14 au 20 juillet à Prague.</p>
<p>Le CFP est ouvert jusqu’au 27 janvier : <a class="inline-onebox" href="https://programme.europython.eu/europython-2025/">EuroPython 2025 :: pretalx</a></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/europython-2025-14-au-20-juillet/2433/1">EuroPython 2025</a></p>
<p>2025-07-14 08:00 (Europe/Paris) → 2025-07-20 18:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/europython-2025-14-au-20-juillet/2433">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>copie des fichiers d&#39;un répertoire</title>
        <link href="https://discuss.afpy.org/t/copie-des-fichiers-dun-repertoire/2432" />
        <id>https://discuss.afpy.org/t/copie-des-fichiers-dun-repertoire/2432</id>
        <updated>2025-01-10T16:48:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
je veux copier tous les fichiers d’un répertoire personnel vers un répertoire d’un logiciel accessible par mot de passe, sous Linux et avec python:<br/>
<code>subprocess.call(['gnome-terminal', '--','sudo', '-S', 'cp','-v', path_src+"/nom1.py", path_src+"/nom2.html", path_src+"/nom3.sh", path_dest])</code> fonctionne correctement mais je voudrais ne pas lister tous les fichiers, donc j’ai essayé:<br/>
<code>subprocess.call(['gnome-terminal', '--','sudo', '-S', 'cp','-v', path_src+"/*", path_dest])</code> qui ne fonctionne pas. Merci de me dire pourquoi ?</p>
<p><small>11 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/copie-des-fichiers-dun-repertoire/2432">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Commandes à exécuter pour installer Chrome sur une nouvelle installation Linux Mint</title>
        <link href="https://www.olivierpons.fr/2025/01/10/commandes-a-executer-pour-installer-chrome-sur-une-nouvelle-installation-linux-mint/" />
        <id>https://www.olivierpons.fr/2025/01/10/commandes-a-executer-pour-installer-chrome-sur-une-nouvelle-installation-linux-mint/</id>
        <updated>2025-01-10T07:13:22Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 class="wp-block-heading">Comment installer Google Chrome sur Linux (Ubuntu/Debian) – Guide complet</h2>
<p>Dans ce guide, vous découvrirez comment installer facilement Google Chrome sur votre distribution Linux (Ubuntu ou Debian) en utilisant le terminal. Suivez ces étapes simples pour une installation réussie.</p>
<h2 class="wp-block-heading">Étapes d’installation détaillées</h2>
<ol class="wp-block-list">
<li>Créer le dossier pour les clés de sécurité<br/>
    Cette étape permet de préparer le système pour stocker les clés de sécurité Google.</li>
<li>Télécharger et installer la clé Google<br/>
    Nous récupérons la clé officielle de Google pour garantir l’authenticité des paquets.</li>
<li>Ajouter le dépôt Chrome<br/>
    Configuration du dépôt officiel dans votre système pour accéder aux paquets Chrome.</li>
<li>Mettre à jour la liste des paquets<br/>
    Actualisation de votre système avec le nouveau dépôt ajouté.</li>
<li>Installer Chrome<br/>
    Installation finale du navigateur sur votre système.</li>
</ol>
<h2 class="wp-block-heading">Commandes à exécuter</h2>
<p>Copiez et collez ces commandes une par une dans votre terminal :</p>
<pre class="wp-block-code"><code>sudo mkdir -p /etc/apt/keyrings

curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /etc/apt/keyrings/google-chrome.gpg

echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list

sudo apt update

sudo apt install google-chrome-stable</code></pre>
<h2 class="wp-block-heading">Vérification de l’installation</h2>
<p>Une fois l’installation terminée, vous pouvez :</p>
<ul class="wp-block-list">
<li>Lancer Chrome depuis votre menu d’applications</li>
<li>Ou utiliser la commande <code>google-chrome</code> dans le terminal</li>
</ul>
<p>En cas de problème lors de l’installation, assurez-vous d’avoir les droits administrateur et que votre système est à jour.</p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>[Stage 6 mois - Développement logiciel] - Connexion d&#39;une base de données géographique à une suite logicielle webmapping</title>
        <link href="https://discuss.afpy.org/t/stage-6-mois-developpement-logiciel-connexion-dune-base-de-donnees-geographique-a-une-suite-logicielle-webmapping/2430" />
        <id>https://discuss.afpy.org/t/stage-6-mois-developpement-logiciel-connexion-dune-base-de-donnees-geographique-a-une-suite-logicielle-webmapping/2430</id>
        <updated>2025-01-07T14:15:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2><a class="anchor" href="https://discuss.afpy.org#p-9749-le-contexte-1" name="p-9749-le-contexte-1"></a>Le contexte</h2>
<p><strong><a href="https://geotrek.fr/" rel="noopener nofollow ugc">Geotrek </a>est une suite logicielle webmapping 100% libre dédiée à la gestion et à la valorisation des sentiers et activités outdoor</strong> pour les territoires publics (Parcs naturels régionaux, Parcs nationaux, départements etc).</p>
<p>C’est une solution 4 en 1 qui se compose notamment de Geotrek-Admin, un backoffice pour les gestionnaires. Actuellement Geotrek-Admin est ancré dans un large écosystème et permet l’export de données via une API vers de nombreuses plateformes. Il est également possible pour les territoires d’importer des données depuis plusieurs sources (Systèmes d’Informations Touristiques (SIT) comme Apidae ou Tourinsoft, signalements depuis Suricate, etc.) et pour cela un système générique de Parsers a été implémenté.</p>
<p>Certains territoires toutefois, n’ont pas accès à des SIT, ont peu de données à importer lors d’une installation, ou tout simplement souhaiteraient enrichir les contenus avec des objets issus d’autres plate-formes. En réponse à ce besoin, OpenStreetMap (OSM), base de données géographique libre et collaborative propose des objets qui pourraient avoir leur place dans Geotrek et permettrait d’enrichir les offres d’itinéraires proposés.</p>
<p><em>Découvrez<a href="https://makina-corpus.com/references" rel="noopener nofollow ugc"> quelques uns de nos projets</a> et retrouvez-nous sur <a href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Welcome to the Jungle</a></em>.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9749-la-mission-2" name="p-9749-la-mission-2"></a>La mission</h2>
<p>Vous interviendrez au sein d’une équipe <strong>pluridisciplinaire</strong> composée notamment de développeurs front end et back end, d’experts SIG, et sous leur responsabilité <strong>vous aurez pour mission de conduire le projet de la phase d’exploration à la phase de livraison</strong> :</p>
<ul>
<li>
<p>Exploration : monter en compétence sur l’architecture de Geotrek, son modèle de données, le métier associé; recueillir les besoins existants auprès de l’équipe Makina Corpus mais aussi auprès d’utilisateur·ice·s de la communauté Geotrek; analyser les données existantes dans OSM ;</p>
</li>
<li>
<p>Planification / Gestion de projet : proposer une matrice de correspondance entre les données OSM et Geotrek, être force de proposition sur la méthodologie de suivi de la réalisation du projet ;</p>
</li>
<li>
<p>Réalisation : mettre en place l’architecture technique de la solution, réalisation de tests unitaires ;</p>
</li>
<li>
<p>Livraison : déploiement d’une nouvelle version de Geotrek-Admin incluant les développements réalisés, communication auprès de la communauté sur la nouvelle fonctionnalité.</p>
</li>
</ul>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9749-profil-3" name="p-9749-profil-3"></a>Profil</h2>
<p>Vous préparez un Bac+5 en informatique et <strong>possédez des bases solides en développement web et en versioning avec Git, GitHub; ainsi que les processus classiques de développement en équipe. Vous avez une première expérience en Python</strong>, idéalement avec le framework Django.</p>
<p>Vous êtes familier avec le concept d’API REST et le protocole HTTP.</p>
<p>Vous êtes autonome et curieu.se, et aimez proposer des solutions. Le développement cartographique vous intéresse.</p>
<p><em>Geotrek étant une solution libre et opensource nous apportons une grande importance à la qualité du code réalisé et aux tests. Aussi le code réalisé sera relu et validé par l’équipe de Makina Corpus tout au long du stage.</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9749-informations-complmentaires-4" name="p-9749-informations-complmentaires-4"></a>Informations complémentaires</h2>
<p><strong>Pourquoi faire votre stage chez nous ?</strong></p>
<p>Dans la ruche collaborative Makina Corpus on dit ce qu’on fait : les équipes évoluent dans une ambiance motivante et stimulante (projets et contrib Opensource, participations encouragées à des évènements/meetup , émulation entre personnes passionnées, technos innovantes à tester, veille…) et contribuent aux valeurs humaines ancrées dans l’ADN de l’entreprise (environnement, équilibre vie pro/vie privée, collaboratif…).</p>
<p>Mais surtout chez Makina on fait ce qu’on dit : vous avez besoin de le voir pour le croire ? Venez nous rencontrer, un.e makinien.ne pourra vous en parler !</p>
<p><strong><a href="https://recrutement@makina-corpus.com" rel="noopener nofollow ugc">Écrivez-nous</a> et racontez qui vous êtes et ce qui vous anime</strong>. Expliquez-nous en quoi vos motivations et vos compétences sont en adéquation avec nos valeurs et nos activités. <em>N’hésitez pas à nous montrer votre code si ça vous dit !</em></p>
<p><strong>Plus d’informations sur notre processus de recrutement :</strong></p>
<p>Nous répondons à chacune des candidatures de manière personnalisée et dans un délai que nous essayons de rendre le plus raisonnable possible. Si votre candidature est sélectionnée, voici comment cela va se passer pour vous :</p>
<ul>
<li>un 1° échange en visio vous sera proposé par Lise notre RRH afin de faire plus ample connaissance et de déterminer si vous, comme nous, souhaitons aller plus loin ;</li>
<li>il y aura ensuite un 2° entretien avec deux membres de l’équipe technique : ce sera l’occasion de parler technique et sujet de stage.</li>
</ul>
<p>La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/stage-6-mois-developpement-logiciel-connexion-dune-base-de-donnees-geographique-a-une-suite-logicielle-webmapping/2430">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>[Stage 6 mois - Développement logiciel] - Création d&#39;une interface d&#39;administration d&#39;un outil de valorisation des sentiers et activités outdoor</title>
        <link href="https://discuss.afpy.org/t/stage-6-mois-developpement-logiciel-creation-dune-interface-dadministration-dun-outil-de-valorisation-des-sentiers-et-activites-outdoor/2429" />
        <id>https://discuss.afpy.org/t/stage-6-mois-developpement-logiciel-creation-dune-interface-dadministration-dun-outil-de-valorisation-des-sentiers-et-activites-outdoor/2429</id>
        <updated>2025-01-07T14:15:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><strong><a href="https://makina-corpus.com/" rel="noopener nofollow ugc">Makina Corpus </a>développe des projets web ou mobiles d’envergure</strong> combinant notamment la cartographie, l’intelligence artificielle, le traitement et l’analyse de données, la dataviz. Nos applications phares sont au service de domaines tels que la randonnée et la gestion d’espaces naturels (Geotrek), l’aménagement du territoire (Actif), l’accès aux cartographies pour les déficients visuels (Accessimap), des systèmes d’information territoriale, des interfaces d’exploration de données…</p>
<p><strong>Notre organisation et nos prestations se construisent sur trois piliers</strong> : les logiciels libres, le respect de l’humain et l’engagement en faveur de l’environnement; trois valeurs fondamentales que nous développons et renforçons grâce à notre charte RSE.</p>
<p>Découvrez <a href="https://makina-corpus.com/references" rel="noopener nofollow ugc">quelques uns de nos projets</a> et retrouvez-nous sur <a href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Welcome to the Jungle</a>.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9748-le-contexte-1" name="p-9748-le-contexte-1"></a>Le contexte</h2>
<p><a href="https://geotrek.fr/" rel="noopener nofollow ugc">Geotrek </a><strong>est une suite logicielle webmapping 100% libre</strong> dédiée à la gestion et à la valorisation des sentiers et activités outdoor pour les territoires publics. C’est une solution 4 en 1 qui se compose notamment de <a href="https://github.com/GeotrekCE/Geotrek-rando-v3" rel="noopener nofollow ugc">Geotrek-Rando</a>, un site Internet promotionnel pour des visiteurs du territoire.</p>
<p><strong>L’objectif du stage</strong> sera de créer une application permettant d’interfacer graphiquement une personnalisation d’un Geotrek Rando. Aujourd’hui la personnalisation se fait manuellement par l’édition de fichiers <code>json</code>, <code>.html</code> et de dépôts de médias (images, vidéos, etc.). Cette application permettrait d’accompagner le gestionnaire pour faire cette saisie avec un contrôle des erreurs, une prévisualisation du rendu et faire un export facilement utilisable.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9748-la-mission-2" name="p-9748-la-mission-2"></a>La mission</h2>
<p>Vous interviendrez au sein d’une équipe <strong>pluridisciplinaire</strong> composée notamment de développeurs front end et back end, d’experts SIG, et sous leur responsabilité <strong>vous aurez pour mission de conduire le projet de la phase d’exploration jusqu’à la phase de livraison :</strong></p>
<ul>
<li>
<p>Exploration : établir une compréhension des interactions entre les différentes solutions Geotrek, recueillir les besoins existants auprès de l’équipe Makina Corpus mais aussi auprès d’utilisateur·ice·s de la communauté Geotrek ;</p>
</li>
<li>
<p>Planification / Gestion de projet : réaliser un planning prévisionnel du projet, être force de proposition sur la méthodologie de suivi de la réalisation du projet ;</p>
</li>
<li>
<p>Réalisation : mettre en place l’architecture technique de la solution, implémentation, développement logiciel ;</p>
</li>
<li>
<p>Livraison : publication du projet sur une forge, déploiement d’une application en ligne permettant de tester le produit auprès de la communauté etc.</p>
</li>
</ul>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9748-profil-3" name="p-9748-profil-3"></a>Profil</h2>
<p><strong>Vous préparez un Bac+5 en informatique et possédez une bonne compréhension de la structure d’une application en JavaScript.</strong> Vous avez une première expérience :</p>
<ul>
<li>Sur une bibliothèque ou un framework populaire tel que React, Vue ou Angular ;</li>
<li>Avec le fonctionnement du HTML/CSS/DOM ;</li>
<li>Sur API REST ;</li>
<li>En bases en versioning avec Git, GitHub et les processus classiques de développement en équipe.</li>
</ul>
<p><em>Savoir réaliser des interfaces graphiques (UI/UX) serait un plus.</em></p>
<p>Geotrek étant une solution libre et opensource nous apportons une grande importance à la qualité du code réalisé et aux tests, le code sera donc relu et validé par l’équipe tout au long du stage.</p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9748-informations-complmentaires-4" name="p-9748-informations-complmentaires-4"></a>Informations complémentaires</h2>
<p><strong>Pourquoi faire votre stage chez nous ?</strong></p>
<p>Dans la ruche collaborative Makina Corpus on dit ce qu’on fait : les équipes évoluent dans une ambiance motivante et stimulante (projets et contrib Opensource, participations encouragées à des évènements/meetup , émulation entre personnes passionnées, technos innovantes à tester, veille…) et contribuent aux valeurs humaines ancrées dans l’ADN de l’entreprise (environnement, équilibre vie pro/vie privée, collaboratif…).</p>
<p>Mais surtout chez Makina on fait ce qu’on dit : vous avez besoin de le voir pour le croire ? Venez nous rencontrer, un.e makinien.ne pourra vous en parler !</p>
<p><strong>Écrivez-nous et racontez qui vous êtes et ce qui vous anime</strong>. Expliquez-nous en quoi vos motivations et vos compétences sont en adéquation avec nos valeurs et nos activités. <em>N’hésitez pas à nous montrer votre code si ça vous dit !</em></p>
<p><strong>En savoir plus sur notre processus de recrutement :</strong></p>
<p>Nous répondons à chacune des candidatures de manière personnalisée et dans un délai que nous essayons de rendre le plus raisonnable possible. Si votre candidature est sélectionnée, voici comment cela va se passer pour vous :</p>
<ul>
<li>un 1° échange en visio vous sera proposé par Lise notre RRH afin de faire plus ample connaissance et de déterminer si vous, comme nous, souhaitons aller plus loin ;</li>
<li>il y aura ensuite un 2° entretien avec deux membres de l’équipe technique : ce sera l’occasion de parler technique et sujet de stage.</li>
</ul>
<p>La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/stage-6-mois-developpement-logiciel-creation-dune-interface-dadministration-dun-outil-de-valorisation-des-sentiers-et-activites-outdoor/2429">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>Chef-Cheffe de projets web junior : climat, agriculture et environnement</title>
        <link href="https://discuss.afpy.org/t/chef-cheffe-de-projets-web-junior-climat-agriculture-et-environnement/2428" />
        <id>https://discuss.afpy.org/t/chef-cheffe-de-projets-web-junior-climat-agriculture-et-environnement/2428</id>
        <updated>2025-01-07T14:15:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><strong>Rejoignez <a href="https://makina-corpus.com" rel="noopener nofollow ugc">Makina Corpus</a></strong> en tant que Chef-Cheffe de projets web junior spécialisé(e) dans les domaines du climat, de l’agriculture et de l’environnement. Intégrez une équipe engagée qui développe des solutions numériques innovantes en combinant cartographie, intelligence artificielle et analyse de données pour répondre aux enjeux environnementaux majeurs.</p>
<p><strong>Vous travaillerez sur des projets qui font sens</strong> tels que la gestion d’espaces naturels et l’aménagement du territoire, en accord avec nos valeurs historiques : logiciels libres, respect de l’humain et engagement écologique. En tant que membre de notre équipe, vous participerez activement à la conception et à la coordination de projets web d’envergure, tout en bénéficiant d’un environnement de travail stimulant qui valorise la collaboration et l’innovation. Si vous êtes motivé par l’idée de contribuer à des projets ayant un impact positif sur le monde, nous serions ravis de vous accueillir chez Makina Corpus.</p>
<p><em>Découvrez <a href="https://makina-corpus.com/references" rel="noopener nofollow ugc">quelques uns de nos projets</a>, et retrouvez-nous sur <a href="https://www.welcometothejungle.com/fr/companies/makina-corpus" rel="noopener nofollow ugc">Welcome To The Jungle</a>.</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9747-la-mission-1" name="p-9747-la-mission-1"></a>La mission</h2>
<p>Vous intégrerez un pôle interdisciplinaire (chefs de projets, ergonomes, graphistes, développeurs Back/Front/Mobile, SIG, DBA…) réparti entre Toulouse, Nantes et Paris, au sein duquel <strong>vous aurez pour mission de piloter les projets de nos clients et de participer de façon active au développement commercial</strong>.</p>
<p><strong><strong>Vos missions consisteront à :</strong></strong></p>
<ul>
<li>Identifier et mettre en œuvre au sein du projet les <strong>besoins technico-fonctionnels</strong> des clients ;</li>
<li>Formaliser, organiser, planifier et contrôler les phases de réalisation ;</li>
<li><strong>Piloter et coordonner</strong> l’équipe projet ;</li>
<li>Assurer le suivi du planning et le contrôle de la qualité ;</li>
<li>Gérer les <strong>engagements vis-à-vis du client</strong> et s’assurer de sa satisfaction ;</li>
<li><strong>Fidéliser</strong>, entretenir et développer le portefeuille client existant ;</li>
<li>Participer aux phases d’avant-vente en relation avec le client et avec nos équipes, rédiger une proposition commerciale.</li>
</ul>
<p><em>Nous mettrons en place un plan de formation et un accompagnement par plusieurs chefs de projets</em> <em>adapté pour vous permettre d’acquérir rapidement une très bonne connaissance de l’entreprise, son activité et son environnement, et de vous approprier et maîtriser les techniques de gestion de projet web exigeants.</em></p>
<p><em>Ce poste est ouvert au télétravail partiel (jusqu’à 3 jours/semaine).</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9747-profil-2" name="p-9747-profil-2"></a>Profil</h2>
<p><strong>Vous maîtrisez les méthodes et outils de gestion de projets web complexes et techniques, et une expérience de minimum 2 ans sur ce type de poste</strong>. Vous avez une appétence commerciale et idéalement une expérience dans la réponse à appels d’offres.</p>
<ul>
<li>Vous aimez comprendre les besoins du client, s’approprier son métier et lui proposer des solutions adaptées ;</li>
<li><strong>Vous possédez un background technique dans le développement web ;</strong></li>
<li>Votre goût du travail en équipe, votre curiosité, vos excellentes qualités relationnelles seront des atouts indispensables. Apprendre toujours plus vous stimule !</li>
</ul>
<p><em>Nous ne précisons pas de diplôme ou de niveau d’études minimum</em> <em>car nous attachons avant tout de l’importance aux compétences et à la passion du métier.</em></p>
<h2><a class="anchor" href="https://discuss.afpy.org#p-9747-informations-complmentaires-3" name="p-9747-informations-complmentaires-3"></a>Informations complémentaires</h2>
<p>Dans la ruche collaborative Makina Corpus, <strong>on dit ce qu’on fait</strong> : les makiniens évoluent dans une ambiance motivante et stimulante (projets et contrib opensource, participations encouragées à des évènements/meetup, émulation entre experts passionnés, technos innovantes à tester, veille…) et contribuent aux valeurs humaines ancrées dans l’ADN de l’entreprise (environnement, équilibre vie pro/vie privée, collaboratif, télétravail…).</p>
<p>Mais surtout chez Makina <strong>on fait ce qu’on dit</strong> : vous avez besoin de le voir pour le croire ? Venez nous rencontrer, un.e makinien.ne pourra vous en parler ! Nos équipes sont mixtes, femmes et hommes du numérique nous vous attendons.</p>
<p><strong>Écrivez-nous et racontez qui vous êtes et ce qui vous anime</strong>. Expliquez-nous en quoi vos motivations et vos compétences sont en adéquation avec nos valeurs et nos activités.</p>
<p><strong>En savoir plus sur notre processus de recrutement :</strong></p>
<p>Nous répondons à chacune des candidatures de manière personnalisée et dans un délai que nous essayons de rendre le plus raisonnable possible. Si votre candidature est sélectionnée, voici comment cela va se passer pour vous :</p>
<ul>
<li>un 1° échange en visio vous sera proposé par Lise notre RRH afin de faire plus ample connaissance et de déterminer si vous, comme nous, souhaitons aller plus loin ;</li>
<li>il y aura ensuite un 2° entretien avec 2 chefs de projet toulousains : ce sera l’occasion de parler du poste, des missions et des projets ;</li>
<li>enfin, vous serez reçu.e par le responsable de l’agence.</li>
</ul>
<p>La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/chef-cheffe-de-projets-web-junior-climat-agriculture-et-environnement/2428">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>makina</name>
        </author>
    </entry>
    <entry>
        <title>Potato : un outil simple et intégré à Python pour le debug !</title>
        <link href="https://discuss.afpy.org/t/potato-un-outil-simple-et-integre-a-python-pour-le-debug/2427" />
        <id>https://discuss.afpy.org/t/potato-un-outil-simple-et-integre-a-python-pour-le-debug/2427</id>
        <updated>2025-01-07T08:52:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Voir ici : <a class="inline-onebox" href="https://github.com/andrewruba/potato">GitHub - andrewruba/potato: A lightweight tool for debugging and testing Python code. Just type potato in your code and watch your script instantly stop running with a NameError. Zero dependencies. Infinite confusion. Use responsibly.</a></p>
<p><small>3 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/potato-un-outil-simple-et-integre-a-python-pour-le-debug/2427">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Mindiell</name>
        </author>
    </entry>
    <entry>
        <title>MarkItDown pour convertir facilement des fichiers au format Markdown en Python</title>
        <link href="https://linuxfr.org/users/weborator/liens/markitdown-pour-convertir-facilement-des-fichiers-au-format-markdown-en-python" />
        <id>https://linuxfr.org/users/weborator/liens/markitdown-pour-convertir-facilement-des-fichiers-au-format-markdown-en-python</id>
        <updated>2024-12-30T22:20:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://zonetuto.fr/python/markitdown-convertir-des-pdf-powerpoint-word-et-excel-en-markdown/">https://zonetuto.fr/python/markitdown-convertir-des-pdf-powerpoint-word-et-excel-en-markdown/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137812/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/weborator/liens/markitdown-pour-convertir-facilement-des-fichiers-au-format-markdown-en-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>weborator</name>
        </author>
    </entry>
    <entry>
        <title>Pycon Austria 2025 - invitation</title>
        <link href="https://discuss.afpy.org/t/pycon-austria-2025-invitation/2423" />
        <id>https://discuss.afpy.org/t/pycon-austria-2025-invitation/2423</id>
        <updated>2024-12-30T14:13:13Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Mesdames et Messieurs,<br/>
Je voudrais vous inviter chaleureusement à Pycon Autriche 2025.</p>
<p>Malheureusement, mon français n’est pas assez bon pour le reste du message, je vais donc écrire en anglais:</p>
<p>Please share the following message among your members:</p>
<p>There will be a free international Python conference in Austria from 6th to 7th April 2025:<br/>
<a href="https://at.pycon.org/" rel="noopener nofollow ugc">https://at.pycon.org</a></p>
<p>(conference language will be English)</p>
<p>Entrance is for free but registration as a visitor, volunteer or speaker is necessary. Please register now because our places are limited.</p>
<p>It will be a conference about the Python programming language with free entrance for visitors, free community tables for python-related groups and open-source projects and paid tables for sponsors. Among talks and workshops, there will be recruiting sessions and talks / workshops dedicated to using Python in education.<br/>
Would you be interested to represent your group with a table (or a poster / booklets / advertising material) at the conference ?<br/>
It is the goal of the conference to make it easy for visitors to connect with active people from the python community in person. It is also a goal of the conference to present to conference visitors many parts of the complex Python ecosystem of libraries and open-source projects that are connected with the Python programming language.<br/>
Also, if possible, could you please spread the message about the conference and print out and publish this poster :<br/>
<a class="onebox" href="https://drive.google.com/drive/folders/1peXO4pThfR289gb1hpT4Elq-hVodoMtT" rel="noopener nofollow ugc" target="_blank">https://drive.google.com/drive/folders/1peXO4pThfR289gb1hpT4Elq-hVodoMtT</a></p>
<p>greetings from Vienna,<br/>
-Horst JENS</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/pycon-austria-2025-invitation/2423">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>horstjens</name>
        </author>
    </entry>
    <entry>
        <title>Problème permission zsh</title>
        <link href="https://discuss.afpy.org/t/probleme-permission-zsh/2421" />
        <id>https://discuss.afpy.org/t/probleme-permission-zsh/2421</id>
        <updated>2024-12-26T16:57:33Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour<br/>
Tout nouveau, dans le monde de python, j’essaye d’exécuter un script que j’ai trouvé sur ChatGPT pouvant permettre grâce à la caméra de faire bouger la souris. Voici le script.</p>
<pre><code class="lang-python">import cv2
import pyautogui

# Chargement du classificateur de visage
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# Initialisation de la capture vidéo
cap = cv2.VideoCapture(0)

# Boucle principale
while True:
# Capture d'une image
ret, frame = cap.read()
if not ret:
break

# Conversion en niveaux de gris
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# Détection des visages
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)

# Pour chaque visage détecté
for (x, y, w, h) in faces:
# Calcul de la position du centre du visage
center_x = x + w // 2
center_y = y + h // 2

# Déplacement de la souris
screen_width, screen_height = pyautogui.size()
pyautogui.moveTo(center_x * screen_width / frame.shape[1], center_y * screen_height / frame.shape[0])

# Dessiner un rectangle autour du visage (pour visualiser)
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
</code></pre>
<p>L’ordinateur sur lequel j’essaye d’exécuter le script est un iMac tournant sur Catalina. Lorsque je glisse le script dans ma console, j’ai le message ci-dessous.<br/>
</p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.afpy.org/uploads/default/original/2X/e/e92cb1ada4b69d2966ef5645f54ccf95f39c9c78.png" title="Capture d’écran 2024-12-26 à 17.56.06"><img alt="Capture d’écran 2024-12-26 à 17.56.06" height="276" src="https://discuss.afpy.org/uploads/default/optimized/2X/e/e92cb1ada4b69d2966ef5645f54ccf95f39c9c78_2_690x276.png" width="690"/></a></div><p></p>
<p>La version python installée sur l’ordinateur est la version 2.7.16</p>
<p><small>11 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/probleme-permission-zsh/2421">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>sg72</name>
        </author>
    </entry>
    <entry>
        <title>Placement de widget</title>
        <link href="https://discuss.afpy.org/t/placement-de-widget/2419" />
        <id>https://discuss.afpy.org/t/placement-de-widget/2419</id>
        <updated>2024-12-26T09:15:01Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
sujet certainement trivial mais je ne comprends pas la différence entre:</p>
<pre><code class="lang-python">lab1=Label(fen1, text = "label dans fen1", bg='bisque', font=("Verdana", 10))
lab1.place(x=xl, y=yl)
</code></pre>
<p>et<br/>
<code>lab1=Label(fen1, text = "label dans fen1", bg='bisque', font=("Verdana", 10)).place(x=xl, y=yl)</code><br/>
je n’ai pas trouvé d’explication mais c’est sûr il y a une différence de fonctionnement <img alt=":slightly_smiling_face:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slightly_smiling_face.png?v=12" title=":slightly_smiling_face:" width="20"/></p>
<p><small>7 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/placement-de-widget/2419">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>La galère de Python en déploiement</title>
        <link href="https://linuxfr.org/users/abriotde/journaux/la-galere-de-python-en-deploiement" />
        <id>https://linuxfr.org/users/abriotde/journaux/la-galere-de-python-en-deploiement</id>
        <updated>2024-12-23T22:58:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-un-peu-dhistoire">Un peu d'histoire</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-les-langages-interpr%C3%A9t%C3%A9s">Les langages interprétés</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-un-cas-concret-le-miens">Un cas concret: le miens</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-ma-solution--docker">Ma solution : Docker</a></li>
<li><a href="https://linuxfr.org/tags/python/public.atom#toc-en-langage-compil%C3%A9">En langage compilé</a></li>
</ul>
<p>Dans un <a href="https://linuxfr.org/users/pulkomandy/liens/apprendre-la-programmation-en-python-n-est-pas-plus-facile-qu-en-java-ou-en-c">lien</a> récent sur LinuxFR, j'ai défendu la simplicité de mise en oeuvre de Python par rapport à C++…du moins au moins pour un POC, ou un petit script perso. Mais quand on développe un soft un peu plus complexe, eh bien j'avoue que pour ce qui est de tout le reste, autre que le pur développement, Python perd largement de son intérêt. Ou du moins, un bon langage compilé comme C++ , (je préfère, Rust) y gagne.</p>
<h2 id="toc-un-peu-dhistoire">Un peu d'histoire</h2>
<p>Si l'on a vanté la portabilité de C lors de sa sortie, ce n'est pas parce qu'un programme fonctionne tel quel sur n'importe quel OS/Architecture, mais parce qu'il compile a peu près sans changement, sur toute les architectures/OS. A l'époque, on programmait beaucoup en Assembleur ou alors chaque OS avait son propre langage. En C, on avait, et c'est toujours vrai, qu'a recompiler. Et même s'il peut toujours y avoir une dépendance a l'OS (Appels système) ou à l'Architecture (Big-Endian, Little-Endian), sur un OS/Architecture, on a qu'a vérifier les PATH et librairies… et si elles manque, c'est relativement simple à rajouter. On peut même compiler avec les librairies (empaqueter) (Sauf la libC).</p>
<h2 id="toc-les-langages-interprétés">Les langages interprétés</h2>
<p>Depuis les premier OS, on a eu besoin de pouvoir lancer des programmes sans paser nécéssairement, par l'étape de compilation. Le premier langage interprété "en live" est le Shell (Bash, pour les Linuxien). L'énorme avantage, pour le développeur, c'est qu'il n'y a plus de risque de segfault (Il y a d'autres risque qui y sont du coup exacerbés, mais ce n'est pas le sujet). Cependant, il introduit un problème: c'est que le programme peut être parfaitement correct mais planter si l'interpréteur n'est pas à jour ou même parfois trop récent s'il n'y a pas de rétro-compatibilité. Et ça, c'est un véritable problème a plus d'un niveau pour le déploiement.</p>
<p>Si ce problème existe pour tout les langage interprété, paradoxalement, c'est quand la gestion des dépendance est trop simplifié et que le langage évolue trop qu'il est exacerbé.<br/>
Bash étant quasiment immuable (on peut parfois le déplorer), on a rarement des problèmes de ce type (Mais bien d'autres ;) ).<br/>
Pour Java, on galère, souvent avec les dépendances, mais somme toute le problème est assez limité. Comme c'est assez complexe d'ajouter des librairies, on en ajoute assez peu…<br/>
Pour Python, à contrario, c'est exacerbé. Comme on a des utilitaires comme PIP, on a trop souvent beaucoup de dépendances en cascades. Évidemment, les dépendances évitent de réinventer la roue. Cependant, pour chacune on a des contraintes sur leurs dépendances, voir sur la version du langage. On peut arriver au final a devoir gérer des dépendances complexes entre dépendances.<br/>
Les environnement virtuels, permettent simplement d'éviter les conflits avec les autres dépendances installées sur l'OS, mais on garde la même version du langage.</p>
<h2 id="toc-un-cas-concret-le-miens">Un cas concret: le miens</h2>
<p>Je développe <a href="https://github.com/abriotde/openhems-sample">OpenHEMS</a>, un soft en Python, car c'est simple et que je m'appuie sur Home-Assistant et qu'au départ je voulais me contenter d'un script Home-Assistant. Ce soft intègre en dépendance le code-source (Car ce n'est plus complexe autrement) d'<a href="https://github.com/davidusb-geek/emhass">Emhass</a> car ce soft intègre une gestion par IA éprouvé des panneaux solaires. Évidemment, j'ai envie de disposer de la dernière version d'Emhass (pour ne pas avoir les bugs, et les meilleurs fonctionnalités). Seulement, il utilise des fonctionnalités Python 3.10 (Je ne sais plus lesquels) et je souhaites le faire tourner sur une carte Open-Hardware (conformément à ma philosophie Open-Source) : <a href="https://www.olimex.com/Products/OLinuXino/A64/A64-OLinuXino/open-source-hardware">Olinuximo</a>. Seulement, OLinuXino ne propose que Debian 11 (C'est maintenu mais pas le dernier) et avec je n'ai que Python 3.9.<br/>
Au départ, j'ai pensé recompilé Python sur l'OS et l'embarqué. Cela me permet de gérer comme je veux mes dépendances. Oui mais voilà, ce n'est pas si simple, la compilation a fonctionné, mais je ne disposait pas de toutes les fonctionnalités. J'ai laissé tombé.<br/>
J'avais aussi voulu installé Emhass avec pip, mais le problème était plus grave encore, il m'installait une très ancienne version incompatible car elle avait été mal configuré. Et ce même avec Python3.12.</p>
<h2 id="toc-ma-solution--docker">Ma solution : Docker</h2>
<p>La manière la plus simple que j'ai trouvé (et sécurisé sans trop pénaliser les performances) c'est d'utiliser Docker. Mais du coup il faut se lancer dans une compilation docker (Avec Github).<br/>
Avec Docker OpenHEMS est beaucoup plus simple tester.<br/>
C'est aussi vrai que Docker sécurise OpenHEMS. Cela évite qu'une faille OpenHEMS permette de compromettre l'OS. De ce point de vue, c'est même plus sécurisé que de le faire tourner sous un user dédié. Mais cela coupe de tous les passe droits. Quand le logiciel tourne sous docker, il ne dispose pas de tous les accès à l'OS. Or OpenHEMS utilisait certains passe-droits:<br/>
1. Il tournait en root, ce qui me permettait de lancer le VPN pour un accès maintenance. Par sécurité (vie privé et autres), je ne veux pas laisser le VPN tourner en permanence. Je veux que l'utilisateur puisse autoriser manuellement la maintenance. J'ai donc utilisé un process root, un "pseudo-cron" qui se lance avec incron quand un fichier est modifié dans un répertoire spécifique.<br/>
2. Les logs étaient directement écris dans le /var/log/openhems, il faut un montage (Mais j'ai encore des problèmes là).</p>
<p>En fait, on peut lancer OpenHEMS sur Python 3.9 sans docker, mais on ne disposera pas de l'option Emhass ce qui est bloquant si l'on dispose de panneaux solaires…</p>
<p>PS : Peut-être n'ais-je pas fait les meilleurs choix. Je suis ouvert aux réflexions en commentaires.</p>
<h2 id="toc-en-langage-compilé">En langage compilé</h2>
<p>En langage compilé, (Rust j'aimerai), j'aurais certainement codé moins vite, mais j'aurais été plus rapide sur le déploiement. Concrètement, le problème de dépendance est géré à la compilation et on l'oublie trop souvent. Cette galère que j'ai bien connu en C/C++ évite bien des tracas après.<br/>
On ne peut pas dire qu'il n'y ait plus du tout de problème de dépendances. Tout le chalenge des distributions est de géré les conflits de version des librairies dynamiques. C'est tout de même minimisé.<br/>
En Python, c'est a un tel niveau que les distributions disposent toujours de Python2 en sus de Python3 (Alors que cela date) et que maintenant, on ne peut plus installer de dépendance avec pip (sur Debian du moins). On a accès qu'aux version disponibles et gérées par les mainteneurs de la distribution.</p>
<div><a href="https://linuxfr.org/users/abriotde/journaux/la-galere-de-python-en-deploiement.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137772/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/abriotde/journaux/la-galere-de-python-en-deploiement#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>abriotde</name>
        </author>
    </entry>
    <entry>
        <title>UV un énième packageur python</title>
        <link href="https://linuxfr.org/users/jeanclaude-2/journaux/uv-un-enieme-packageur-python" />
        <id>https://linuxfr.org/users/jeanclaude-2/journaux/uv-un-enieme-packageur-python</id>
        <updated>2024-12-23T10:17:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>On se moque facilement des projets js qui vont et qui viennent mais python n’est pas en reste avec ses <em>toolchains</em>. Pour moi qui n’utilise pas beaucoup python, je dois perpétuellement me référer à la série d’articles pour vérifier quel outil est la “bonne” façon de faire (ou en tout cas pas trop désuète) et comment l’appeler (parce que <code>python -m pip install requests</code> ne me vient pas du premier coup). </p>
<p>Et l’autre jour on m’a dit qu’il y avait un outil qui a l’air super : uv. Encore un nouveau, super. Il lave plus blanc que blanc, il rend le poil brillant, il fait revenir l’être aimé,… ? Bien sûr et pour cocher toutes les cases il est écrit en rust.</p>
<p>Bon il s’avère que j’étais sur un petit outil en python donc essayons la doc d’installation :</p>
<pre><code class="sh">curl -LsSf https://astral.sh/uv/install.sh <span class="p">|</span> sh</code></pre>
<p>(Quand je vais leur raconter ça sur linuxfr, faudra que ce soit un vendredi.)</p>
<p>Et l’usage ?</p>
<ul>
<li>créer un projet ? <code>uv init dossier</code>
</li>
<li>ajouter une dépendance ? <code>uv add ma-super-bibliothèque</code>
</li>
<li>lancer mon projet ? <code>uv run mon-script.py</code>
</li>
</ul>
<p>Ok c’est rapide ça utilise un environnement virtuel, ça m’a créé quelques fichiers</p>
<ul>
<li><code>pyproject.toml</code></li>
<li><code>uv.lock</code></li>
<li><code>.env/</code></li>
<li><code>.python-version</code></li>
</ul>
<p>Ouai je vois bien à quoi sert chaque fichier.</p>
<p>Au final pour mon usage simple ça fait le job très bien. Je ne sais pas s’il peut servir à créer des <em>wheel</em> comme il faut etc, mais pour ce que je fais de python il a l’air simple et efficace. Il installe les dépendances plus vite que <code>pip</code> et les commandes sont simples à mémoriser.</p>
<div><a href="https://linuxfr.org/users/jeanclaude-2/journaux/uv-un-enieme-packageur-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137763/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jeanclaude-2/journaux/uv-un-enieme-packageur-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>barmic 🦦</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;automne 2024</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2024" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2024</id>
        <updated>2024-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://pygments.org/">Pygments</a></h2>
<p><em>Bibliothèque Python de coloration syntaxique</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/issues/2747">Ajout d'un lexeur pour colorer les fichiers *.sources</a>. Ce format de fichiers remplacera à terme les fichiers <code>sources.list</code> dans Debian et dérivées.</li>
<li>Suite à une réflexion faite par un mainteneur de <code>pygments</code> concernant <a href="https://github.com/pygments/pygments/issues/2603">l'utilisation du mauvais lexeur</a> pour la coloration syntaxique dans Sphinx, des corrections ont été proposées dans <a href="https://github.com/kivy/kivy/pull/8910">Kivy</a>, <a href="https://github.com/bokeh/bokeh/issues/14137">Bokeh</a> (<a href="https://github.com/bokeh/bokeh/pull/14138">rapport associé</a>) et <a href="https://github.com/PaddlePaddle/Paddle/pull/69135">Paddle</a>.</li>
</ul>
<h2><a href="https://pypi.org/project/pluralizefr/">Pluralizefr</a></h2>
<p><em>Bibliothèque Python pour obtenir un mot au pluriel à partir du singulier</em></p>
<ul>
<li><a href="https://github.com/sblondon/pluralizefr/pull/8">Suppression des préfixes <code>u</code></a> devant les chaînes de caractères</li>
<li><a href="https://github.com/sblondon/pluralizefr/commit/dd20244f8e510ceb8ebbd49bad57a17b4b1c34e2">Suppression de setup.py</a>, remplacé par pyproject.toml</li>
<li><a href="https://github.com/sblondon/pluralizefr/pull/6">Ajout d'une commande pour envoyer des paquets vers pypi.org</a></li>
<li><a href="https://github.com/sblondon/pluralizefr/pull/9">Ajout de métadonnées dans pyproject.toml</a></li>
<li><a href="https://github.com/sblondon/pluralizefr/pull/10">Correction du cas « oeil »</a></li>
<li>Publications sur <a href="https://pypi.org/project/pluralizefr/">pypi.org</a></li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Ensemble d'outils et de bibliothèques pour la console PSP de Sony</em></p>
<ul>
<li>Amélioration de la lisibilité des valeurs du stick analogique dans le code d'exemple des controleurs <a href="https://github.com/pspdev/pspsdk/pull/237">dans le dépôt principal</a> et <a href="https://github.com/pspdev/pspdev.github.io/pull/64">pour le site web</a></li>
<li><a href="https://github.com/pspdev/pspdev.github.io/pull/63">Correction d'un commentaire dans du code d'exemple</a></li>
</ul>
<h2>apt-setup</h2>
<p><em>Partie de Debian-Installer. Produit un fichier /etc/apt/sources.list pour le système installé</em></p>
<ul>
<li><a href="https://salsa.debian.org/installer-team/apt-setup/-/merge_requests/19">Suppression du script inutilisé pour le cas d'une Ubuntu</a></li>
</ul>
<h2><a href="https://gitlab.com/sblondon/bmg">bmg</a></h2>
<p><em>Déplace un fichier (ou répertoire) pendant 3 minutes. Une fois le délai expiré, le fichier (ou répertoire) revient.</em></p>
<p>Principalement :</p>
<ul>
<li><a href="https://gitlab.com/sblondon/bmg/-/commit/2c4f149ca72562f146b3388a2045601702bd3bab">le faire fonctionner</a></li>
<li>...et ajouter les notifications de bureau supplémentaires pour <a href="https://gitlab.com/sblondon/bmg/-/commit/dc03615c792e560c785b90bd76ad816cb7535313">kdialog</a>, <a href="https://gitlab.com/sblondon/bmg/-/commit/430e464072ab73ba245e5c28eb638e802ab519f2">zenity et xmessage </a></li>
</ul>
<h2><a href="https://canaille.readthedocs.io">Canaille</a></h2>
<p><em>Serveur d’identité et d'autorisations ultra-léger</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/Canaille/#history">1 nouvelle version</a> durant cette saison.</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/181">Correction d'un lien dans la documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/182">Implémentation d'un indicateur de robustesse des mots de passe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/184">Mise à jour vers HTMX 2.0.3</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/185">Journalisation des évènements de sécurité</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/186">Support de Python 3.13</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/187">Migration de Poetry à uv</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/188">Test de la compromission des mots de passe avec l'API HIPB</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/189">Documentation de la configuration de la ligne de commande</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/190">Mise en place de l'internationalisation de la documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/191">Documentation des cas d'usage</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/192">Correction d'une coquille dans les URLs de certains mails</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/193">Implémentation de mécanismes d'authentification multi-facteurs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/194">Implémentation du verrouillage des comptes après tentatives de connexion infructueuses</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/195">Correction d'une coquille</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/196">Implémentation du flux OIDC <code>client_credentials</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/197">Implémentation de l'API SCIM</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/198">Correction d'une coquille</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/199">Correction de ponctuation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/201">Correction de ponctuation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/202">Documentation de l'habillage personnalisé</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/203">Implémentation de l'expiration des mots de passe</a></li>
<li>Divers correctifs sur les tests unitaires <a href="https://gitlab.com/yaal/canaille/-/merge_requests/204">1</a>, <a href="https://gitlab.com/yaal/canaille/-/merge_requests/205">2</a>, <a href="https://gitlab.com/yaal/canaille/-/merge_requests/206">3</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-models/#history">11 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/79">Les attributs <code>attributes</code> et <code>excluded_attributes</code> de SearchRequest sont mutuellement exclusifs</a></li>
<li><a href="https://github.com/python-scim/scim2-models">Sérialisation des attributs <code>Base64</code>,</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/81">Validateur s'assurant que les ids des Schemas sont des URIs</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/82">Migration de Poetry à uv</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/83">Configuration native de Tox</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/87">Comparaison des attributs immutables dans les requêtes de remplacement de ressources</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-server">scim2-server</a></h2>
<p><em>Prototype de server SCIM2 ultra-léger</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-server/#history">1 nouvelle version</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-server/pull/3">Le préfixe <code>/v2</code> est facultatif</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/7">Migration de Poetry à uv</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/8">Support de Python 3.10</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Fabrication et analyse pythonique de requêtes SCIM</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-client/#history">12 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/23">Migration de Poetry à uv</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/24">Correction d'une erreur surverant lorsque les serveurs ne retournent pas l'en-tête <code>content-type</code></a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/25">Vérification du typage avec Mypy</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/27">Séparation des logiques métier et réseau</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/28">Implémentation d'un moteur réseau basé sur Werkzeug</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/29">Implémentation d'un moteur asynchrone basé sur HTTPX</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>Outil de vérification de conformité de serveurs aux normes SCIM</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-tester/#history">8 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/12">Migration de Poetry à uv</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-cli">scim2-cli</a></h2>
<p><em>Outil en ligne de commandes pour interagir avec des applications SCIM</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/scim2-cli/#history">3 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-cli/pull/10">Documentation sur la manière de fabriquer des binaires</a></li>
<li><a href="https://github.com/python-scim/scim2-cli/pull/11">Migration de Poetry à uv</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/wtforms">wtforms</a></h2>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/WTForms/#history">2 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/pallets-eco/wtforms/pull/854">Migration vers l'organisation pallets-eco</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/855">Arrêt du support de Python 3.8, support de Python 3.13</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/856">Configuration de <code>pre-commit</code> basée sur celle de Flask</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/857">Correction d'une coquille sur un message d'avertissement</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/859">Suppression de code déprécié</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/860">Intégration continue basée sur celle de Flask</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/862">Correction d'une erreur d'import apparue avec la version 3.2.0</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/flask-wtf">flask-wtf</a></h2>
<p><em>Intégration de WTForms dans Flask</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/Flask-WTF/#history">1 nouvelle version</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/602">Migration vers l'organisation pallets-eco</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/603">Arrêt du support de Python 3.8, support de Python 3.13</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/604">Configuration de <code>pre-commit</code> basée sur celle de Flask</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/607">Mise à jour de <code>pre-commit</code></a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/wtforms-sqlalchemy">wtforms-sqlalchemy</a></h2>
<p><em>Intégration de SQLAlchemy dans WTForms</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/WTForms-SQLAlchemy/#history">1 nouvelle version</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/49">Méga-nettoyage (migration vers pallets-eco, support modèrne de Python, pre-commit, pyproject.toml)</a></li>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/50">Mise à jour des dépendances de la documentation</a></li>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/51">Support de Python 3.13</a></li>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/51">Intégration continue basée sur celle de Flask</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/click">click</a></h2>
<p><em>Boîte à outil pour créer des programme en ligne de commande composables avec Python</em></p>
<ul>
<li><a href="https://github.com/pallets/click/pull/2818">Ajout d'un paramètre <code>catch_exceptions</code> à <code>CLIRunner</code></a></li>
</ul>
<h2><a href="https://github.com/sphinx-contrib/jinja-autodoc">jinja-autodoc</a></h2>
<p><em>Documentation automatique des patrons Jinja avec Sphinx</em></p>
<p>Nous avons publié <a href="https://pypi.org/project/jinja-autodoc/#history">3 nouvelles versions</a> durant cette saison.</p>
<ul>
<li><a href="https://github.com/offlinehacker/sphinxcontrib.jinjadomain">Fork du projet sphinxcontrib.jinjadomain, et hébergement dans l'organisation sphinx-contrib</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Autumn 2024 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2024" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2024</id>
        <updated>2024-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://pygments.org/">Pygments</a></h2>
<p><em>Pygments is a generic syntax highlighter written in Python</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/issues/2747">Add a lexer to highlight *.sources files</a>. This format will replace the <code>sources.list</code> format in Debian and derivatives.</li>
<li>An issue written by a <code>pygments</code> maintainer about <a href="https://github.com/pygments/pygments/issues/2603">the use of the wrong lexer</a> for syntax highlighting in Sphinx, some fixes have been pushed to <a href="https://github.com/kivy/kivy/pull/8910">Kivy</a>, <a href="https://github.com/bokeh/bokeh/issues/14137">Bokeh</a> (<a href="https://github.com/bokeh/bokeh/pull/14138">linked issue</a>) and <a href="https://github.com/PaddlePaddle/Paddle/pull/69135">Paddle</a>.</li>
</ul>
<h2><a href="https://pypi.org/project/pluralizefr/">Pluralizefr</a></h2>
<p><em>Python library to get plural word from singular one</em></p>
<ul>
<li><a href="https://github.com/sblondon/pluralizefr/pull/8">Remove of <code>u</code> prefix</a> before strings</li>
<li><a href="https://github.com/sblondon/pluralizefr/commit/dd20244f8e510ceb8ebbd49bad57a17b4b1c34e2">Remove of setup.py</a>, remplaced by pyproject.toml</li>
<li><a href="https://github.com/sblondon/pluralizefr/pull/6">Add a command to send package to pypi.org</a></li>
<li><a href="https://github.com/sblondon/pluralizefr/pull/9">Add metadata in pyproject.toml</a></li>
<li><a href="https://github.com/sblondon/pluralizefr/pull/10">Fix 'oeil' case</a></li>
<li>Publish releases on <a href="https://pypi.org/project/pluralizefr/">pypi.org</a></li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Collection of tools and libraries written for Sony's Playstation Portable (PSP) gaming console</em></p>
<ul>
<li>Make analog stick values more readable in basic control sample <a href="https://github.com/pspdev/pspsdk/pull/237">in main repository</a> and <a href="https://github.com/pspdev/pspdev.github.io/pull/64">in website</a></li>
<li><a href="https://github.com/pspdev/pspdev.github.io/pull/63">Fix a comment about sprite in example code</a></li>
</ul>
<h2>apt-setup</h2>
<p><em>Part of Debian-Installer. Generate an /etc/apt/sources.list for the installed system</em></p>
<ul>
<li><a href="https://salsa.debian.org/installer-team/apt-setup/-/merge_requests/19">Delete unused ubuntu generator script</a></li>
</ul>
<h2><a href="https://gitlab.com/sblondon/bmg">bmg</a></h2>
<p><em>It moves a file (or directory) for 3 minutes. At the time out, the file (or directory) comes back.</em></p>
<p>Mainly:</p>
<ul>
<li><a href="https://gitlab.com/sblondon/bmg/-/commit/2c4f149ca72562f146b3388a2045601702bd3bab">get it works</a></li>
<li>...and add additional desktop notifications for <a href="https://gitlab.com/sblondon/bmg/-/commit/dc03615c792e560c785b90bd76ad816cb7535313">kdialog</a>, <a href="https://gitlab.com/sblondon/bmg/-/commit/430e464072ab73ba245e5c28eb638e802ab519f2">zenity and xmessage </a></li>
</ul>
<h2><a href="https://canaille.readthedocs.io">Canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<p>We published <a href="https://pypi.org/project/Canaille/#history">1 release</a> during this season.</p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/181">Documentation link typo fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/182">Password strenght indicator implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/184">Update to HTMX 2.0.3</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/185">Security events logging</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/186">Support for Python 3.13</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/187">Migration from Poetry to uv</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/188">Password compromission check against the HIPB API</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/189">Documentation on CLI configuration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/190">Documentation translation setup</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/191">Documentation for use cases</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/192">Fix a typo in some mail URLs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/193">Multiple factor authentication implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/194">Intruder lockout implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/195">Typo fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/196">OIDC <code>client_credentials</code> flow implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/197">SCIM server API implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/198">Typo fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/199">Punctuation fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/201">Punctuation fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/202">Documentation on theming</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/203">Password expiry implementation</a></li>
<li>Various unit tests fixes <a href="https://gitlab.com/yaal/canaille/-/merge_requests/204">1</a>, <a href="https://gitlab.com/yaal/canaille/-/merge_requests/205">2</a>, <a href="https://gitlab.com/yaal/canaille/-/merge_requests/206">3</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<p>We published <a href="https://pypi.org/project/scim2-models/#history">11 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-models/pull/79">SearchRequest 'attributes' and 'excluded_attributes' are mutually exclusive</a></li>
<li><a href="https://github.com/python-scim/scim2-models">Base64 attributes serialization</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/81">Validator to ensure Schema ids are URIs</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/82">Migrate from Poetry to uv</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/83">Tox native configuration</a></li>
<li><a href="https://github.com/python-scim/scim2-models/pull/87">Compare immutable attributes in resource replacement requests</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-server">scim2-server</a></h2>
<p><em>Lightweight SCIM2 server prototype</em></p>
<p>We published <a href="https://pypi.org/project/scim2-server/#history">1 release</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-server/pull/3">The <code>/v2</code> prefix is optional</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/7">Migrate from Poetry to uv</a></li>
<li><a href="https://github.com/python-scim/scim2-server/pull/8">Python 3.10 support</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-client">scim2-client</a></h2>
<p><em>Pythonically build SCIM requests and parse SCIM responses</em></p>
<p>We published <a href="https://pypi.org/project/scim2-client/#history">12 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-client/pull/23">Migrate from Poetry to uv</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/24">Fix an error happening when server don't return the <code>content-type</code> header</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/25">Type checking with Mypy</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/27">Separation of business and network logic</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/28">Werkzeug engine implementation</a></li>
<li><a href="https://github.com/python-scim/scim2-client/pull/29">Async HTTPX engine implementation</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-tester">scim2-tester</a></h2>
<p><em>SCIM RFCs server compliance checker</em></p>
<p>We published <a href="https://pypi.org/project/scim2-tester/#history">8 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-tester/pull/12">Migrate from Poetry to uv</a></li>
</ul>
<h2><a href="https://github.com/python-scim/scim2-cli">scim2-cli</a></h2>
<p><em>SCIM application development CLI</em></p>
<p>We published <a href="https://pypi.org/project/scim2-cli/#history">3 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/python-scim/scim2-cli/pull/10">Document how to build binaries</a></li>
<li><a href="https://github.com/python-scim/scim2-cli/pull/11">Migrate from Poetry to uv</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/wtforms">wtforms</a></h2>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<p>We published <a href="https://pypi.org/project/WTForms/#history">2 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/pallets-eco/wtforms/pull/854">Migrate to the pallets-eco organization</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/855">Stop support for Python 3.8, start support for Python 3.13</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/856">pre-commit configuration based of Flask</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/857">Typo on a warning message</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/859">Remove deprecated code</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/860">GHA workflows based on Flask</a></li>
<li><a href="https://github.com/pallets-eco/wtforms/pull/862">Fix import issues appeared in the 3.2.0 release</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/flask-wtf">flask-wtf</a></h2>
<p><em>Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.</em></p>
<p>We published <a href="https://pypi.org/project/Flask-WTF/#history">1 release</a> during this season.</p>
<ul>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/602">Migrate to the pallets-eco organization</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/603">Stop support for Python 3.8, start support for Python 3.13</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/604">pre-commit configuration based of Flask</a></li>
<li><a href="https://github.com/pallets-eco/flask-wtf/pull/607">pre-commit update</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/wtforms-sqlalchemy">wtforms-sqlalchemy</a></h2>
<p><em>WTForms integration for SQLAlchemy</em></p>
<p>We published <a href="https://pypi.org/project/WTForms-SQLAlchemy/#history">1 release</a> during this season.</p>
<ul>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/49">mega clean-up (move to pallets-eco, modern python support, pre-commit, pyproject.toml)</a></li>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/50">doc dependencies update</a></li>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/51">support for Python 3.13</a></li>
<li><a href="https://github.com/pallets-eco/wtforms-sqlalchemy/pull/51">GHA workflow based on Flask</a></li>
</ul>
<h2><a href="https://github.com/pallets-eco/click">click</a></h2>
<p><em>Python composable command line interface toolkit</em></p>
<ul>
<li><a href="https://github.com/pallets/click/pull/2818">Add a <code>catch_exceptions</code> parameter to <code>CLIRunner</code></a></li>
</ul>
<h2><a href="https://github.com/sphinx-contrib/jinja-autodoc">jinja-autodoc</a></h2>
<p><em>Automatically document your Jinja templates with Sphinx</em></p>
<p>We published <a href="https://pypi.org/project/jinja-autodoc/#history">3 releases</a> during this season.</p>
<ul>
<li><a href="https://github.com/offlinehacker/sphinxcontrib.jinjadomain">Fork from sphinxcontrib.jinjadomain, and hosting under the sphinx-contrib organization umbrella</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Nouvelles fonctionnalités de sécurité implémentées dans Canaille</title>
        <link href="https://yaal.coop/blog/canaille-nlnet-security-features" />
        <id>https://yaal.coop/blog/canaille-nlnet-security-features</id>
        <updated>2024-12-18T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Nous avons travaillé récemment sur les principales caractéristiques de sécurité de Canaille, dans le cadre de notre <a href="https://nlnet.nl">subvention NLNet</a>.</p>
<h1>Sécurité</h1>
<p>Au cours de ce sprint, nous nous sommes concentrés sur la mise en œuvre des recommandations de sécurité conseillées par l'<a href="https://cyber.gouv.fr/publications/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe">agence publique française de cybersécurité "ANSSI"</a>.</p>
<h2>Authentification multifactorielle</h2>
<p>Autrefois, il suffisait de demander un mot de passe pour vérifier l'identité d'une personne sur l'internet.
Cependant, il existe de multiples façons de deviner un mot de passe ou de le voler à quelqu'un, et les utilisateurs ont rapidement commencé à prendre des habitudes peu recommandables à leur égard, comme l'utilisation du même mot de passe sur tous les sites web.
Mais il n'y a pas que les mots de passe.
Les développeurs de logiciels se sont rendu compte que, surtout pour les applications sensibles, il n'est pas possible d'utiliser une seule méthode d'authentification : chacune d'entre elles présente des faiblesses et peut éventuellement être piratée.</p>
<p>La solution a consisté à demander aux utilisateurs de s'authentifier à l'aide d'au moins deux méthodes d'authentification, ou facteurs - d'où le nom d'authentification multifactorielle.</p>
<p>Pour un logiciel de gestion de l'identité comme Canaille, il s'agissait d'une fonctionnalité essentielle, et nous l'avons mise en œuvre pour quatre méthodes différentes :</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/HMAC-based_one-time_password">Mot de passe à usage unique basé sur HMAC (HOTP)</a></li>
<li><a href="https://en.wikipedia.org/wiki/Time-based_one-time_password">Mot de passe à usage unique basé sur le temps (TOTP)</a></li>
<li>Code envoyé par e-mail</li>
<li>Code envoyé par SMS</li>
</ul>
<p>Les méthodes HOTP/TOTP exigent que l'utilisateur télécharge et configure une application mobile ou un logiciel d'authentification (comme <a href="https://freeotp.github.io/">FreeOTP</a>), qui produira à son tour des mots de passe à usage unique.
Ces mots de passe changent périodiquement (chaque fois que vous appuyez sur le bouton de votre authentificateur pour HOTP, ou après une période fixe pour TOTP), ce qui rend plus difficile pour les attaquants de mettre la main sur un mot de passe et de l'utiliser à temps.
Ce sont probablement les facteurs d'authentification les plus sûrs actuellement disponibles pour Canaille.</p>
<p>Les deux autres facteurs (codes par e-mail ou SMS) sont plus basiques mais offrent une meilleure sécurité lorsqu'ils sont combinés au mot de passe.
Ils pourraient être adaptés à des cas d'utilisation où la facilité d'utilisation semble plus importante que la sécurité.
La méthode du e-mail exige que les administrateurs de l'instance Canaille aient configuré un serveur <a href="https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">SMTP</a>.
De même, un serveur <a href="https://en.wikipedia.org/wiki/Short_Message_Peer-to-Peer">SMPP</a> fonctionnel est nécessaire pour la méthode SMS.</p>
<p>Ces facteurs peuvent être cumulés, jusqu'à 3 facteurs différents (HOTP et TOTP, en utilisant la même application d'authentification, s'excluent mutuellement) en plus du mot de passe traditionnel.
L'utilisateur devra alors remplir tous les codes requis pour se connecter à son compte.
La fonction MFA peut également être complètement désactivée - dans ce cas, l'utilisateur n'aura besoin que de son mot de passe pour se connecter.</p>
<h2>Verrouillage anti-intrusion</h2>
<p>Pour empêcher les attaques par force brute sur les comptes Canaille, nous avons ajouté un délai entre chaque tentative de connexion échouée.
Ce délai est doublé chaque fois qu'un utilisateur saisit un mot de passe erroné.
Nous avons également envisagé de verrouiller les comptes après un certain nombre de tentatives infructueuses, mais cela aurait permis aux attaquants de verrouiller trop facilement tous les comptes d'utilisateurs.</p>
<h2>Journalisation des événements de sécurité</h2>
<p>Afin de faciliter la détection d'une attaque potentielle sur une instance de Canaille, nous avons ajouté la journalisation des événements sensibles.
Ces journaux sont marqués d'une étiquette spéciale "sécurité" pour faciliter leur récupération.</p>
<p>Les événements de sécurité enregistrés comprennent les tentatives d'authentification, les mises à jour de mot de passe ou d'e-mail, l'émission ou la révocation de jetons OAuth, <a href="https://canaille.readthedocs.io/en/latest/features.html#logging">etc</a>.</p>
<h2>Vérification de la compromission du mot de passe</h2>
<p>Comme les utilisateurs ont tendance à réutiliser les mêmes mots de passe (avec quelques petites variations dans le meilleur des cas), il est désormais possible de vérifier si chaque nouveau mot de passe ne se trouve pas dans une base de données de mots de passe compromis, grâce à l'API de <a href="https://haveibeenpwned.com/">Have I Been Pwned</a>.</p>
<p>HIBP offre un point de terminaison API gratuit qui peut être consulté pour les mots de passe compromis.</p>
<h2>Politique d'expiration des mots de passe</h2>
<p>Afin d'accroître la sécurité des comptes d'utilisateurs, il est désormais possible de déterminer une durée de vie pour les mots de passe.
Lorsqu'un mot de passe expire, les utilisateurs sont obligés de le mettre à jour lors de leur prochaine connexion, ou pendant leur session s'ils sont déjà connectés.</p>
<h1>Approvisionnement avec SCIM</h1>
<p>Canaille fournit une implémentation de serveur SCIM, qui peut être utilisée par les applications clientes pour gérer les utilisateurs et les groupes directement dans Canaille (avec les droits d'autorisation).
À l'avenir, nous aimerions créer une petite application de gestion d'abonnements à des services, et SCIM est un protocole bien adapté pour qu'une telle application puisse communiquer avec Canaille.</p>
<p>Grâce à <a href="https://yaal.coop/blog/en/scim2-toolbox">nos récents travaux sur SCIM</a>, nous avions presque tout prêt pour ajouter une implémentation côté serveur de SCIM.
C'était aussi un moyen de tester nos bibliothèques SCIM en situation réelle.
Au final, cette intégration nous a fait corriger beaucoup de choses aussi bien dans notre boîte à outils SCIM que dans Canaille.</p>
<h1>Documentation</h1>
<h2>Internationalisation</h2>
<p>Pour rendre Canaille plus accessible, nous avons passé du temps à rendre notre documentation traduisible.
L'interface de traduction est disponible sur <a href="https://hosted.weblate.org/projects/canaille/documentation/">Weblate</a>.
Nous avons également traduit la <a href="https://canaille.readthedocs.io/fr">documentation en français</a> pour valider le mécanisme.
Ce fut également l’occasion pour nous de revoir toute la documentation existante et de corriger les erreurs de formulation et les fautes de frappe.</p>
<h2>Habillage</h2>
<p>Nous avons également travaillé sur la <a href="https://canaille.readthedocs.io/en/latest/tutorial/theming.html">documentation sur la personnalisation de l'habillage de Canaille</a> pour aider les utilisateurs à personnaliser l'apparence de leur instance Canaille.
Nous souhaitions référencer et documenter <a href="https://canaille.readthedocs.io/en/latest/references/templates.html">tous nos patrons</a>, pour aider les designers à les modifier.
Pour y parvenir, nous avons dû <a href="https://github.com/offlinehacker/sphinxcontrib.jinjadomain">transformer une ancienne bibliothèque non maintenue</a> en une nouvelle bibliothèque <a href="https://jinja-autodoc.readthedocs.io">jinja-autodoc</a> pour la génération automatique de documentation de patrons.
Nous l'avons nettoyé, apporté quelques améliorations et l'avons placé sous l' organisation <a href="https://github.com/sphinx-contrib">sphinx-contrib</a>.</p>
            </div>
        </content>
        <author>
            <name>Sébastien Birolleau &lt;sebastien@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>New security features implemented in Canaille</title>
        <link href="https://yaal.coop/blog/en/canaille-nlnet-security-features" />
        <id>https://yaal.coop/blog/en/canaille-nlnet-security-features</id>
        <updated>2024-12-18T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>We have been working recently on key security features for Canaille, as parts of our <a href="https://nlnet.nl">NLNet grant</a>.</p>
<h1>Security</h1>
<p>During this sprint we focused on implementing security recommandations advised by the <a href="https://cyber.gouv.fr/publications/recommandations-relatives-lauthentification-multifacteur-et-aux-mots-de-passe">French cybersecurity public agency "ANSSI"</a>.</p>
<h2>Multi-factor Authentication</h2>
<p>In the old days, asking for a password was considered sufficient to verify the identity of a person on the internet.
However, there are multiple ways to guess a password or steal it from someone, and users quickly began to form less than ideal habits around them - like using the same password on every websites.
But it's not just passwords.
Software developers came to the realization that, especially for sensitive applications, you can't get away with using a single authentication method: every one of them has its weaknesses, and can eventually be cracked.</p>
<p>The solution was found in asking users to authenticate themselves using two or more authentication methods, or factors - hence the name multi-factor authentication.</p>
<p>For an identity management software like Canaille, this was a key feature to have, and we implemented it for four different methods:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/HMAC-based_one-time_password">HMAC-based one-time password (HOTP)</a></li>
<li><a href="https://en.wikipedia.org/wiki/Time-based_one-time_password">Time-based one-time password (TOTP)</a></li>
<li>Code sent via email</li>
<li>Code sent via SMS</li>
</ul>
<p>The HOTP/TOTP methods require the user to download and set up an authenticator mobile app or software (like <a href="https://freeotp.github.io/">FreeOTP</a>), which will in turn produce one-time passwords.
These passwords change periodically (each time you press the button in your authenticator for HOTP, or after a fixed period for TOTP), which makes it harder for attackers to get their hands on a password and use it in time.
These are probably the most secure authentication factors available now for Canaille.</p>
<p>The remaining two factors (codes via email or SMS) are more basic but still offer a better security when combined with the password.
They might be adapted for use cases where ease of use appears more important than security.
The email method requires the administrators of the Canaille instance to have configured a <a href="https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">SMTP</a> server.
Likewise, a functioning <a href="https://en.wikipedia.org/wiki/Short_Message_Peer-to-Peer">SMPP</a> server is needed for the SMS method.</p>
<p>These factors can be stacked, up to 3 different factors (HOTP and TOTP, using the same authenticator app, are mutually exclusive) in addition to the traditional password.
The user will then need to fill out all the required codes in order to log in to their account.
The MFA feature can also be deactivated completely - in that case the user will only need their password to login.</p>
<h2>Intruder lockout</h2>
<p>To prevent brute-force attacks on Canaille accounts, we added a delay between each failed login attempt.
The delay doubles each time someone enters a wrong password.
We also considered locking accounts after a given number of failed attempts, but this would have made it too easy for attackers to lock all user accounts.</p>
<h2>Security events logging</h2>
<p>In order to facilitate the detection of a potential attack on a Canaille instance, we added logging for sensitive events.
Those logs are marked with a special "security" tag for easy retrieval.
They can be configured to be written in a separate file than usual log entries.</p>
<p>Logged security events include authentication attempts, password or email updates, emission or revokation of OAuth tokens, and <a href="https://canaille.readthedocs.io/en/latest/features.html#logging">more</a>.</p>
<h2>Password compromise investigation</h2>
<p>Since users tend to reuse the same passwords (with some small variations in the best case), it is now possible to check if each new password is not in a compromised passwords database, thanks to the <a href="https://haveibeenpwned.com/">Have I Been Pwned</a>'s API.</p>
<p>HIBP offers a free API endpoint that can be consulted for compromised passwords.</p>
<h2>Password expiry policy</h2>
<p>In order to increase the security of user accounts, it is now possible to determine a lifetime for passwords.
When a password expires, users are forced to update their password on their next login, or during their session if already logged in.</p>
<h1>Provisioning with SCIM</h1>
<p>Canaille provides a SCIM server implementation, that can be used by client applications to manage users and group directly in Canaille (given the rights permissions).
In the future we would love to build a small service subscription management application, and SCIM is a well suited protocol for such an application to communicate with Canaille.</p>
<p>Thanks to <a href="https://yaal.coop/blog/en/scim2-toolbox">our recent work on SCIM</a> we had almost everything ready to add a server-side implementation of SCIM.
It was also a way to test our SCIM libraries in a real-world situation.
In the end, this integration made us fix a lot of things both in our SCIM toolbox and in Canaille.</p>
<h1>Documentation</h1>
<h2>Internationalization</h2>
<p>To make Canaille more accessible, we spent some time to make our translation translatable.
The translation interface is available on <a href="https://hosted.weblate.org/projects/canaille/documentation/">Weblate</a>.
We also translated the <a href="https://canaille.readthedocs.io/fr">documentation in French</a> to validate the mechanism.
This was also an opportunity for us to review all the existing documentation and fix wording errors and typos.</p>
<h2>Theming</h2>
<p>We also have worked on the <a href="https://canaille.readthedocs.io/en/latest/tutorial/theming.html">theming documentation</a> to help users customize how their Canaille instance looks.
We wanted to reference and document <a href="https://canaille.readthedocs.io/en/latest/references/templates.html">all our templates</a>, to help designers modify them.
To achieve this we had to <a href="https://github.com/offlinehacker/sphinxcontrib.jinjadomain">fork an old unmaintained library</a> into a new library <a href="https://jinja-autodoc.readthedocs.io">jinja-autodoc</a> for automatic template documentation generation.
We cleaned it, made a few improvements, and pushed it under the <a href="https://github.com/sphinx-contrib">sphinx-contrib</a> organization.</p>
            </div>
        </content>
        <author>
            <name>Sébastien Birolleau &lt;sebastien@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>EuroPython 2025 − Call for Contributors</title>
        <link href="https://discuss.afpy.org/t/europython-2025-call-for-contributors/2404" />
        <id>https://discuss.afpy.org/t/europython-2025-call-for-contributors/2404</id>
        <updated>2024-12-17T10:45:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>L’<a href="https://ep2025.europython.eu/">EuroPython 2025</a> aura lieu du 14 au 20 juillet à Prague et l’appel à contributeurices / volontaires <a href="https://forms.gle/kY7jqSJTjEhFccWJ6">est ouvert</a>.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/europython-2025-call-for-contributors/2404">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>CDI Dev Odoo / Python - Coopérative Commown à Strasbourg</title>
        <link href="https://linuxfr.org/forums/general-petites-annonces/posts/cdi-dev-odoo-python-cooperative-commown-a-strasbourg" />
        <id>https://linuxfr.org/forums/general-petites-annonces/posts/cdi-dev-odoo-python-cooperative-commown-a-strasbourg</id>
        <updated>2024-12-14T12:56:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 id="toc-notre-coopérative-">Notre coopérative :</h2>
<p>Commown est une coopérative (SCIC) qui soutient le mouvement naissant de l’électronique responsable par la location longue durée d’appareils électroniques aussi éthiques et écologiques que possible.</p>
<p><strong>Plus qu’une simple coopérative de location, Commown :</strong></p>
<ul>
<li>Fait du lobbying d’intérêt général aux côtés d’autres associations du domaine comme Halte à l’Obsolescence Programmée, <a href="https://forum.commown.coop/t/le-lobbying-dinteret-general-chez-commown/3126">voir cet article</a>;</li>
<li>Soutient les producteurs responsables : achats, soutien de marketing, relai de services, financement de R&amp;D ;</li>
<li>Crée et gère des biens communs comme notre logiciel libre de gestion des locations de longue durée publié sur <a href="https://github.com/commown">notre GitHub</a>
</li>
<li>Sensibilise ses bénéficiaires à l’emprise des GAFAM et au respect de la vie privée sur internet et dans la téléphonie mobile.</li>
</ul>
<h2 id="toc-vos-missions-">Vos missions :</h2>
<p>Au siège de Commown à Strasbourg, vous rejoindrez l’équipe Outils informatiques et vous contribuerez :</p>
<ul>
<li>Au développement du système de gestion et à l’amélioration des outils internes</li>
<li>À la consolidation des systèmes en production et à la sûreté des données</li>
</ul>
<p><strong>Ainsi, vous pourrez travailler sur :</strong></p>
<ul>
<li>Le développement et la maintenance du logiciel de gestion de toute l’activité de Commown : l’ERP Open Source Odoo, version communautaire, muni de nombreux modules développés et maintenus par l’OCA (Odoo Community Association)</li>
<li>Intégration de modules OCA pour nos besoins fonctionnels par encore ou mal couverts : assemblage, logistique, réparation…</li>
<li>Développement de nouveaux modules pour nos besoins spécifiques (ergonomie, interaction avec d’autres services, extension de nos activités…)</li>
<li>Maintenance fonctionnelle et corrective de <a href="https://github.com/commown/commown-odoo-addons/">nos modules actuels</a>
</li>
<li>Migration vers les nouvelles versions Odoo (tous les 3 ans environ)</li>
<li>La spécification des besoins internes (ceux de nos équipes) ou externes (ceux des bénéficiaires de nos services). Ceci requiert l’apprentissage de domaines fonctionnels extrêmement variés, de la vente en ligne à la logistique en passant par la comptabilité, le support, la gestion de parcs d’appareils etc.</li>
<li>La maintenance corrective et évolutive des outils liés à Odoo : CI, serveurs de test et de production, outils de sauvegarde, outils de déploiement, etc.</li>
<li>La gestion de notre intranet et des outils informatiques mis à disposition de nos équipes (gestionnaire de mot de passe, nextcloud, etc.), en fonction de votre expérience acquise au sein de Commown et de vos appétences</li>
</ul>
<h2 id="toc-nous-recherchons-une-personne-qui-">Nous recherchons une personne qui :</h2>
<ul>
<li>À un intérêt marqué pour ce type de projet : écologique, éthique, coopératif, bien commun (logiciel libre)</li>
<li>S’intègre facilement dans une équipe et communique bien avec les autres</li>
<li>À une bonne capacité d’abstraction et de modélisation de connaissances variées</li>
<li>Aime comprendre de manière approfondie les sujets techniques</li>
<li>Favorise la logique et la connaissance dans la résolution de problèmes</li>
<li>Aime aller au bout des choses : rendre des travaux terminés, fonctionnels, bien testés et documentés, pensés pour la maintenance future</li>
<li>Sait apprendre en permanence, par la veille, la lecture, la réflexion méthodologique</li>
<li>Cherche un emploi en phase avec ses valeurs</li>
</ul>
<p><strong>Compétences idéales</strong></p>
<ul>
<li>Bonne connaissance du fonctionnement du web (protocoles, back et front)</li>
<li>Connaissance théorique et pratique du langage python et de sa librairie standard</li>
<li>Pratique fluide de git ou mercurial dans un contexte de travail collectif</li>
<li>Maîtrise élémentaire du shell posix</li>
<li>Notions et un peu d’expérience pratique de l’administration-système sous Linux</li>
<li>Idéalement expérience d’interaction avec des communautés du logiciel libre</li>
</ul>
<h2 id="toc-modalités">Modalités</h2>
<ul>
<li>CDI</li>
<li>Télétravail possible plusieurs jours par semaine</li>
<li>Lieu de travail : Strasbourg ; distanciel complet envisageable à terme</li>
<li>Pour postuler/relayer l'annonce : <a href="https://nuage.commown.coop/s/rmS76BGYxYp7FbZ">https://nuage.commown.coop/s/rmS76BGYxYp7FbZ</a>
</li>
</ul>
<p><strong>NB 1 :</strong> Nous avons conscience que le père Noël n’existe pas, si vous n’avez pas toutes les compétences de notre liste, mais que notre projet vous motive, postulez !</p>
<p><strong>NB 2 :</strong> Nous mettons tout en place pour que le monde de l’électronique ne reste pas majoritairement masculin et que les femmes se sentent à l’aise chez nous.</p>
<p><strong>NB 3 :</strong> Lieux de travail : Strasbourg, full distanciel possible à terme</p>
<div><a href="https://linuxfr.org/forums/general-petites-annonces/posts/cdi-dev-odoo-python-cooperative-commown-a-strasbourg.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137631/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/general-petites-annonces/posts/cdi-dev-odoo-python-cooperative-commown-a-strasbourg#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Adrien-Commown</name>
        </author>
    </entry>
    <entry>
        <title>Retours sur les meetups en mixité choisie</title>
        <link href="https://discuss.afpy.org/t/retours-sur-les-meetups-en-mixite-choisie/2402" />
        <id>https://discuss.afpy.org/t/retours-sur-les-meetups-en-mixite-choisie/2402</id>
        <updated>2024-12-13T14:23:52Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Au cours de la saison de meetups dernière, on avait organisé des meetups en mixité choisie sur Lyon.</p>
<p><a class="mention" href="https://discuss.afpy.org/u/tut-tuuut">@tut-tuuut</a> et Morgane, qui ont participé à l’orga et aux évènèments, ont écrit un article pour le calendrier de l’avant de Paris Web pour en parler : <a class="inline-onebox" href="https://www.24joursdeweb.fr/2024/rencontres-en-non-mixite-choisie-retour-d-experience-et-mise-en-perspective">Rencontres en non-mixité choisie : retour d’expérience et mise en perspective — 24 jours de web</a></p>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/retours-sur-les-meetups-en-mixite-choisie/2402">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Livrer un environnement Python</title>
        <link href="https://linuxfr.org/forums/programmation-python/posts/livrer-un-environnement-python" />
        <id>https://linuxfr.org/forums/programmation-python/posts/livrer-un-environnement-python</id>
        <updated>2024-12-11T15:05:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>Si je développe un truc en Python, je peux faire les choses proprement en me faisant un environnement virtuel (j'aime bcp <code>venv</code>). Ensuite avec un <code>pip freeze</code> j'ai ma liste des packages.</p>
<p>Bon, mais si quelqu'un désire utiliser mon travail, il va devoir se recréer un environnement virtuel, y faire son <code>pip install</code>, le sourcer puis ensuite exécuter mon code.</p>
<p>Est-ce qu'il existerait un truc plus immédiat, à la <code>appimage</code>, où tu peux tout empaqueter prêt à l'emploi ?</p>
<p>Merci !</p>
<div><a href="https://linuxfr.org/forums/programmation-python/posts/livrer-un-environnement-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137606/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/programmation-python/posts/livrer-un-environnement-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>gUI</name>
        </author>
    </entry>
    <entry>
        <title>uv : guide complet du nouveau gestionnaire de packages Python rapide et ambitieux</title>
        <link href="https://www.saaspegasus.com/guides/uv-deep-dive/" />
        <id>https://www.saaspegasus.com/guides/uv-deep-dive/</id>
        <updated>2024-12-11T11:16:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez pourquoi et comment adopter uv, le gestionnaire de packages révolutionnaire qui transforme l’écosystème Python. Ce guide détaillé vous présente ses fonctionnalités innovantes, ses avantages, et ses usages pour optimiser vos projets Python.</p>
<a href="https://news.humancoders.com/t/python/items/27255-uv-guide-complet-du-nouveau-gestionnaire-de-packag"><img src="https://www.saaspegasus.com/static/images/web/uv/uv-social.d765bb4ede7a.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/27255-uv-guide-complet-du-nouveau-gestionnaire-de-packag#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/27255-uv-guide-complet-du-nouveau-gestionnaire-de-packag">uv : guide complet du nouveau gestionnaire de packages Python rapide et ambitieux</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Boîte à outils SCIM en Python</title>
        <link href="https://yaal.coop/blog/scim2-toolbox" />
        <id>https://yaal.coop/blog/scim2-toolbox</id>
        <updated>2024-12-04T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Nos copains d’<a href="https://indiehosters.net">IndieHosters</a> proposent à leurs utilisateurs un <a href="https://indiehosters.net/apps">catalogue de services</a> étoffé.
Leur métier est de gérer toute l’infrastructure autour de ces services, et un des enjeux importants du métier est la gestion des utilisateurs.</p>
<p>Lorsqu’un nouveau compte utilisateur est créé auprès d’un serveur d’identité, généralement le jeton d'accès que l’utilisateur transmet aux services contient les informations nécessaires à la création du compte utilisateur auprès de ces services.
Prenons un exemple avec le serveur d’identité Keycloak et le service d’hébergement de fichiers Nextcloud :</p>
<ul>
<li>je crée mon compte utilisateur auprès de Keycloak (par exemple, en remplissant un formulaire d’inscription),</li>
<li>je tente d’accéder à Nextcloud, mais je n’ai pas de session ouverte, je suis donc redirigé vers Keycloak,</li>
<li>je m’identifie, Keycloak génère un jeton contenant mes informations personnelles,</li>
<li>ce jeton est transmis à Nextcloud,</li>
<li>Nextcloud lit mes informations personnelles dans le jeton.
  Si mon compte utilisateur n’existait pas sur Nextcloud, alors il est créé.
  Sinon, mes informations personnelles sont mises à jour dans Nextcloud.</li>
<li>Nextcloud m’autorise enfin l’accès aux fichiers.</li>
</ul>
<p>C’est très pratique, mais ça ne couvre pas tous les cas de figure :</p>
<ul>
<li>Comment faire pour partager un document avec un utilisateur qui ne s’est jamais encore connecté à un service ? Pour le moment il est nécessaire d’attendre la première connexion d’un utilisateur avant que son compte ne soit créé sur Nextcloud.</li>
<li>Un utilisateur édite une information le concernant sur le serveur d’identité, par exemple son nom d’affichage. Comment faire pour diffuser l'information instantanément auprès des services (par exemple un compte mail ou un chat qui identifie l'utilisateur par ce même Keycloak) ?Actuellement, les mises à jour d’informations personnelles ne sont répandues sur Nextcloud que lorsque les utilisateurs s’y connectent.</li>
<li>Comment supprimer ou désactiver un compte utilisateur auprès de tous les services ?</li>
</ul>
<p>Pour effectuer toutes ces opérations, on utilise un protocole de <a href="https://fr.wikipedia.org/wiki/Provisionnement">provisionnement</a>.
<em>Provisionner</em> consiste grossièrement à diffuser des modification sur un objet entre plusieurs services.
De nos jours, le protocole de provisionnement souvent utilisé dans l’industrie est <a href="https://simplecloud.info">SCIM</a>.
IndieHosters a préparé une <a href="https://scim.libre.sh">page web d’explications sur le protocole</a> que l’on vous invite à consulter.</p>
<p>IndieHosters a obtenu un financement auprès de <a href="https://nlnet.nl">NLNet</a> pour développer SCIM dans l’écosystème des outils qu’ils utilisent, et ont fait appel à Yaal Coop pour une partie des travaux.
Nous avions plusieurs mission :</p>
<ul>
<li>Fournir un outil en ligne de commandes qui permette de communiquer avec un serveur SCIM, et de tester la conformité d’un serveur SCIM vis-à-vis de la norme.
  Ce projet a donné lieu à plusieurs sous-projets:<ul>
<li><a href="https://scim2-models.readthedocs.io">scim2-models</a>, une bibliothèque Python de sérialisation et validation de ressources SCIM.
  Elle est basée sur <a href="https://docs.pydantic.dev">Pydantic</a> et fournit des objets natifs qui représentent des ressources SCIM et qui implémente une partie de la norme.
  Elle a pour but de servir de brique de base à des serveurs ou des clients SCIM.</li>
<li><a href="https://scim2-client.readthedocs.io">scim2-client</a>, une bibliothèque Python de fabrication et d’analyse pythonique de requêtes SCIM.
  Elle s’appuie sur scim2-models et sur <a href="https://www.python-httpx.org">httpx</a> pour créer des requêtes SCIM, et analyser les réponses des serveurs.</li>
<li><a href="https://github.com/python-scim/scim2-server">scim2-server</a>, un prototype de serveur SCIM développé par <a href="https://www.contact-software.com">CONTACT Software</a> utilisant scim2-models, et co-maintenu par Yaal Coop.</li>
<li><a href="https://scim2-tester.readthedocs.io">scim2-tester</a>, une bibliothèque Python de test de conformité aux normes SCIM. Elle s’appuie sur scim2-client pour envoyer diverses requêtes à un serveur SCIM et observer son comportement en réponse.</li>
<li><a href="https://scim2-cli.readthedocs.io">scim2-cli</a>, un outil en ligne de commandes qui s’appuie sur scim2-client et scim2-tester et qui fournit une interface pour effectuer des opérations simples sur un serveur SCIM.</li>
</ul>
</li>
<li>Proposer l’adoption de SCIM comme protocole officiel de provisionnement dans le protocole de messagerie instantanée <a href="https://matrix.org">Matrix</a>.
  Nous avons rédigé une proposition d’évolution de la norme (<a href="https://github.com/matrix-org/matrix-spec-proposals/pull/4098">MSC4098</a>), pour lesquelles les discussions sont en cours.
  À l’heure actuelle la proposition est toujours à l’étude, mais le principal argument contre est que le provisionnement est hors du périmètre fonctionnel que cherche à couvrir Matrix.</li>
<li>Conjointement à la proposition d’évolution de la norme, nous avons proposé une <a href="https://github.com/element-hq/synapse/pull/17144">implémentation de SCIM dans synapse</a>, le serveur Matrix le plus utilisé actuellement.
  L’implémentation se base sur scim2-models.</li>
</ul>
<p>SCIM nous apparaît comme une norme d'avenir pour le provisionnement et espérons que les bibliothèques que nous avons construites aideront son développement, grâce à de nouveaux outils Python et, à terme, sans ce limiter à ce langage.
Le provisionnement de services est une technique utile aux petit fournisseurs se services en ligne, comme ceux du collectif <a href="https://chatons.org">CHATONS</a>.
Ils font généralement fonctionner ensemble des services hétérogènes, et des normes telles que SCIM aident ces services à communiquer entre eux.
Nous espérons qu'à terme nos travaux permettront d'avoir un impact sur la qualité de service de ces petits fournisseurs, et ainsi aider leur développement.</p>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Python SCIM toolbox</title>
        <link href="https://yaal.coop/blog/en/scim2-toolbox" />
        <id>https://yaal.coop/blog/en/scim2-toolbox</id>
        <updated>2024-12-04T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Our friends from <a href="https://indiehosters.net">IndieHosters</a> provide a rich <a href="https://indiehosters.net/apps">catalog of services</a> to their users.
They are specialized in infrastructure management of those services, and one of the major aspects of their work is the management of user accounts.</p>
<p>When a new user account is created against an identity server, most of the time the access token that the users provide to the services contains information about the user. This information is generally enough to create the users account on the service provider.
Let us study an example with the Keycloak identity provider and a the Nextcloud file management service.</p>
<ul>
<li>the users create their account against Keycloak (for instance by filling a subscription form),</li>
<li>they try to access Nextcloud, but they have no open session, so they get redirected to Keycloak,</li>
<li>they log in, Keycloak generates a token containing their personal information,</li>
<li>this token is forwarded to Nextcloud,</li>
<li>Nextcloud reads the personal information from the token.
  If the user account does not exist on Nextcloud, then it is created.
  Otherwise, the personal information is updated on Nextcloud.</li>
<li>Nextcloud finally gives access to the user.</li>
</ul>
<p>This is convenient, but this does not cover all the use cases:</p>
<ul>
<li>How to share a document with users that never logged in yet?
  For the moment it is needed to wait for a first user login on Nextcloud before its Nextcloud account is created.</li>
<li>Users edit their personal information on the identity server (for instance, their <em>display name</em>).
  How to instantly spread the modification on all the services?
  Currently, personal information are only updated when users log-in anew on the services.</li>
<li>How to delete or deactivate user accounts on all the services, once they have been created?</li>
</ul>
<p>To achieve all those operations, it is needed to use a <a href="https://en.wikipedia.org/wiki/Provisioning_(technology)">provisioning protocol</a>.
<em>Provisioning</em> is the action of forwarding objects (often user and groups) modifications between several services.
These days, the industry standard is <a href="https://simplecloud.info">SCIM</a>.
IndieHosters started a nice <a href="https://scim.libre.sh">presentation webpage</a> about SCIM.</p>
<p>They obtained a <a href="https://nlnet.nl">NLNet</a> grant to develop SCIM in the ecosystem of their tools, and hired Yaal Coop for a part of the project.
We had several missions:</p>
<ul>
<li>Provide a command line interface that would allow to easily communicate with a SCIM server, and test the conformity of a SCIM server towards the specifications.
  This project gave birth to several sub-projects:<ul>
<li><a href="https://scim2-models.readthedocs.io">scim2-models</a>, a SCIM resources validation and serialization Python library.
  It relies on <a href="https://docs.pydantic.dev">Pydantic</a>, provides native objects that implement the SCIM specification.
  It aims to be used as a building block for SCIM server and client applications.</li>
<li><a href="https://scim2-client.readthedocs.io">scim2-client</a>, a Python library that creates and validates SCIM network requests.
  It uses <a href="https://www.python-httpx.org">httpx</a> to handle the network part.</li>
<li><a href="https://github.com/python-scim/scim2-server">scim2-server</a>, a SCIM server prototype that uses <em>scim2-models</em> developped by <a href="https://www.contact-software.com">CONTACT Software</a>, and co-maintained by Yaal Coop.</li>
<li><a href="https://scim2-tester.readthedocs.io">scim2-tester</a>, a SCIM compliance testing Python library.
  It uses scim2-client to send various requests to a SCIM server, and check if it behaves as expected by the SCIM specifications.</li>
<li><a href="https://scim2-cli.readthedocs.io">scim2-cli</a>, a command line utility that uses scim2-client and scim2-tester, and provides an interface to perform various operations on SCIM servers.</li>
</ul>
</li>
<li>Discuss the adoption of SCIM as the official provisioning protocol for the instant messaging protocol <a href="https://matrix.org">Matrix</a>.
  We redacted an evolution request for the protocol (<a href="https://github.com/matrix-org/matrix-spec-proposals/pull/4098">MSC4098</a>), for which discussions are still opened.
  To this day the proposition has not been adopted, the main argument against is that provisioning is out of scope of the Matrix protocol.</li>
<li>In parallel, we developed a <a href="https://github.com/element-hq/synapse/pull/17144">SCIM implementation in synapse</a>, the most famous Matrix server currently. The implementation uses scim2-models.</li>
</ul>
<p>SCIM appears to us a future standard for provisioning and we hope that the libraries developed will help its development, thanks to new Python tools and eventually without limiting this language.
Provisioning is an useful technique for alternative online service providers, such as the ones in the <a href="https://chatons.org">CHATONS</a> collective.
They deploy heterogeneous sets of services, and specifications such as SCIM help those services to communicate.
We hope that in the long run our work will have an impact on the quality of service of those little providers, and help them grow.</p>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Surveiller si fichier modifié par d&#39;autres programmes</title>
        <link href="https://discuss.afpy.org/t/surveiller-si-fichier-modifie-par-dautres-programmes/2398" />
        <id>https://discuss.afpy.org/t/surveiller-si-fichier-modifie-par-dautres-programmes/2398</id>
        <updated>2024-12-04T11:01:32Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>bonjour à tou[te]s</p>
<p>petit souci dans le script :</p>
<pre><code class="lang-python">#!/usr/bin/python -Bu
# -*- coding: utf-8 -*-
import gi,sys
gi.require_version("Gtk","4.0")
from gi.repository import Gtk,Gio
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
class call():
	def back(a,b,c,evt,*_):
		print("*"+str(evt)+"*")
class ecran(Gtk.ApplicationWindow):
	def __init__(self,app,*args,**kwargs):
		Gtk.ApplicationWindow.__init__(self,application=app)
		btn=Gtk.Button(label=	"surveillance de "+sys.argv[0]+
								"\ncliquer pour quitter")
		btn.connect("clicked",self.quitter)
		self.set_child(btn)
		self.present()
		**#======== *mis ici, ça ne donne rien* ========**
**		fich=Gio.File.new_for_path(sys.argv[0])**
**		mon=fich.monitor_file(Gio.FileMonitorFlags.NONE,None)**
**		mon.connect("changed",call.back)**
**		#================**
	def quitter(self,*_):
		self.close()
app=Gtk.Application()
app.connect('activate',ecran)
**"""**
**#======== *mis ici, ça baigne* ========**
**fich=Gio.File.new_for_path(sys.argv[0])**
**mon=fich.monitor_file(Gio.FileMonitorFlags.NONE,None)**
**mon.connect("changed",call.back)**
**#================**
**"""**
app.run(sys.argv)
</code></pre>
<p>je tente de surveiller si un fichier est modifié par un autre programme<br/>
( pour le test, le script lui-même )<br/>
si je place le contrôle dans le corps du programme,<br/>
aucune réaction, alors qu’au lancement, ça marche<br/>
dans mon application j’ai besoin de mettre cette<br/>
surveillance “en dynamique”, au fur et à mesure<br/>
on peut faire comment ?<br/>
merci d’avance</p>
<p><small>6 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/surveiller-si-fichier-modifie-par-dautres-programmes/2398">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>bul</name>
        </author>
    </entry>
    <entry>
        <title>Stage - Développement web (Gap)</title>
        <link href="https://discuss.afpy.org/t/stage-developpement-web-gap/2396" />
        <id>https://discuss.afpy.org/t/stage-developpement-web-gap/2396</id>
        <updated>2024-12-03T16:13:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Le Parc national des Écrins recherche un·e stagiaire en développement web (<a class="hashtag-cooked" href="https://discuss.afpy.org/c/python/8"><span class="hashtag-icon-placeholder"><svg class="fa d-icon d-icon-square-full svg-icon svg-node" xmlns="http://www.w3.org/2000/svg"><use></use></svg></span><span>Python</span></a>, <span class="hashtag-raw">#Flask</span>, <a class="hashtag-cooked" href="https://discuss.afpy.org/tag/django"><span class="hashtag-icon-placeholder"><svg class="fa d-icon d-icon-square-full svg-icon svg-node" xmlns="http://www.w3.org/2000/svg"><use></use></svg></span><span>django</span></a>, <span class="hashtag-raw">#Javascript</span>, <span class="hashtag-raw">#Typescript</span>, <span class="hashtag-raw">#PostgreSQL</span>, <span class="hashtag-raw">#PostGIS</span>, <span class="hashtag-raw">#OpenSource</span> : <a class="inline-onebox" href="https://www.ecrins-parcnational.fr/stage-developpement-web-python-javascript-postgis" rel="noopener nofollow ugc">[STAGE] Développement web (Python, javascript, PostGIS) | Parc national des Ecrins</a></p>
<p>Celui-ci fera une analyse comparative des différentes solutions technologiques et travaillera ensuite sur la modernisation et l’homogénéisation des outils d’inventaire du patrimoine bâti et géologique, ainsi que le suivi des constats de prédation.</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/stage-developpement-web-gap/2396">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>camille_monchicourt</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 19 décembre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-decembre/2395" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-19-decembre/2395</id>
        <updated>2024-12-02T10:51:19Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Meetup de fin d’année le jeudi 19 décembre, dans les locaux de <a href="https://www.lowit.fr/">Lowit</a> (métro Part-Dieu) !</p>
<p>Comme l’an dernier, on vous propose un format Lightning Talks <img alt=":christmas_tree:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/christmas_tree.png?v=12" title=":christmas_tree:" width="20"/></p>
<p>Si vous souhaitez parler de quelque chose, d’une bibliothèque, d’un outil, d’un projet… N’hésitez pas à me contacter pour que je rajoute sur la liste des sujets <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=12" title=":slight_smile:" width="20"/></p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-decembre/2395/1">Lightning Talks de Noël 🎄</a></p>
<p>2024-12-19 19:00 (Europe/Paris) → 2024-12-19 21:30 (Europe/Paris)</p>
</div>
<p><small>4 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-19-decembre/2395">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Sur Toulouse − Meetup le 4 décembre</title>
        <link href="https://discuss.afpy.org/t/sur-toulouse-meetup-le-4-decembre/2393" />
        <id>https://discuss.afpy.org/t/sur-toulouse-meetup-le-4-decembre/2393</id>
        <updated>2024-12-01T13:43:27Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello,</p>
<p>J’ai croisé un post sur LinkedIn.</p>
<p>Il y a un meetup sur Toulouse le mercredi 4 décembre à 18h45 dans les locaux d’Epitech où ça va parler de Django et de Zig.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-toulouse-meetup-le-4-decembre/2393/1">Django DRF et Zig : des APIs simples et du Python rapide 🤯</a></p>
<p>2024-12-04 18:45 (Europe/Paris) → 2024-12-04 20:45 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-toulouse-meetup-le-4-decembre/2393">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>le défi du challenge : qu&#39;affiche ce code</title>
        <link href="https://linuxfr.org/users/serge_ss_paille/journaux/le-defi-du-challenge-qu-affiche-ce-code" />
        <id>https://linuxfr.org/users/serge_ss_paille/journaux/le-defi-du-challenge-qu-affiche-ce-code</id>
        <updated>2024-12-01T09:13:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Demat'iNal</p>
<p>c'est l'époque des sondages on dirait… alors, d'après toi, qu'affiche l'exécution de ce code Python :</p>
<pre><code class="python"><span class="n">e</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">try</span><span class="p">:</span>
    <span class="k">raise</span> <span class="ne">NotImplementedError</span>
<span class="k">except</span> <span class="ne">NotImplementedError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="k">pass</span>
<span class="k">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">e</span><span class="p">))</span></code></pre>
<ol>
<li><code>&lt;class 'int'&gt;</code></li>
<li><code>SyntaxError</code></li>
<li><code>&lt;class 'NotImplementedError'&gt;</code></li>
<li><code>NameError</code></li>
</ol>
<div><a href="https://linuxfr.org/users/serge_ss_paille/journaux/le-defi-du-challenge-qu-affiche-ce-code.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137487/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/serge_ss_paille/journaux/le-defi-du-challenge-qu-affiche-ce-code#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>serge_sans_paille</name>
        </author>
    </entry>
    <entry>
        <title>[Tuto] Raspberry Pi Pico 2 W : mise en route, Wi-Fi et première application</title>
        <link href="https://linuxfr.org/users/colargol/liens/tuto-raspberry-pi-pico-2-w-mise-en-route-wi-fi-et-premiere-application" />
        <id>https://linuxfr.org/users/colargol/liens/tuto-raspberry-pi-pico-2-w-mise-en-route-wi-fi-et-premiere-application</id>
        <updated>2024-11-30T08:05:14Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://next.ink/159862/tuto-raspberry-pi-pico-2-w-mise-en-route-wi-fi-et-premiere-application/">https://next.ink/159862/tuto-raspberry-pi-pico-2-w-mise-en-route-wi-fi-et-premiere-application/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137475/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/colargol/liens/tuto-raspberry-pi-pico-2-w-mise-en-route-wi-fi-et-premiere-application#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Colargol</name>
        </author>
    </entry>
    <entry>
        <title>Effacer terminal</title>
        <link href="https://discuss.afpy.org/t/effacer-terminal/2390" />
        <id>https://discuss.afpy.org/t/effacer-terminal/2390</id>
        <updated>2024-11-27T12:54:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour, encore une petite question de néophyte, désolé:<br/>
j’ai un script qui ouvre (à travers une combo) un terminal où se déroule un script python3. Cela donne:</p>
<pre><code class="lang-python">def sel_mo(event):
	af=ctn.get()
	if af == c1:
		subprocess.run(f"gnome-terminal -- python3 {f1}", shell=True)
	elif af == c2:
		subprocess.run(f"gnome-terminal -- python3 {f2}", shell=True)
	etc...
</code></pre>
<p>je voudrais fermer le terminal quand on change d’item dans la combo puisque je rouvre un terminal à chaque item, mais je n’y arrive pas.<br/>
J’avais essayé un bouton avec <code>subprocess.run("clear", shell=True)</code>, mais cela ne donne rien.<br/>
Auriez-vous une piste ? Merci d’avance</p>
<p><small>8 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/effacer-terminal/2390">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Idées de talk pour les meetups</title>
        <link href="https://discuss.afpy.org/t/idees-de-talk-pour-les-meetups/2388" />
        <id>https://discuss.afpy.org/t/idees-de-talk-pour-les-meetups/2388</id>
        <updated>2024-11-26T16:05:13Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>Je discutais par mail avec Reuven Lerner, un habitué des conférences Python internationales (<a class="inline-onebox" href="https://pyvideo.org/search.html?q=reuven+lerner" rel="noopener nofollow ugc">PyVideo.org</a>).</p>
<p>C’est difficile de trouver des speakers pour les meetups. Il m’a suggéré plein d’idées de talks. Libre à vous d’en proposer au public pour faire que quelques personnes du public deviennent les speakers des prochains meetups.</p>
<p>Je vous mets un bout du mail (en anglais…)</p>
<blockquote>
<p>Here are a few types of conference/meetup talks that could be interesting:</p>
<ol>
<li>How does ___ work behind the scenes?</li>
</ol>
<p>Assignment. Dictionaries. Lists. Importing modules. Grouping in Pandas.<br/>
Functions. This is one of my favorite things to do, because it has<br/>
almost infinite depth, and you’ll surprise yourself with what you find<br/>
in preparing such a talk.</p>
<ol start="2">
<li>___ has changed in Python, and I’ll tell you about it</li>
</ol>
<p>PyArrow in Pandas. Dictionaries (a while ago). Sorting (very recently).<br/>
f-strings.  case-match.</p>
<ol start="3">
<li>You think that ___ is complicated. I’m going to simplify it for you.</li>
</ol>
<p>Decorators. Comprehensions.</p>
<ol start="4">
<li>
<p>Here’s a cool thing that I did in Python. I’ll show it to you, and<br/>
tell you what I learned along the way.</p>
</li>
<li>
<p>Weird and surprising stuff.</p>
</li>
</ol>
</blockquote>
<p>Qu’en pensez-vous ?</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/idees-de-talk-pour-les-meetups/2388">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>vpoulailleau</name>
        </author>
    </entry>
    <entry>
        <title>Sortie du RPi Pico 2 W, version du RPi Pico 2 (cœurs ARM &amp; RISC-V) équipé du Wi-Fi et du Bluetooth</title>
        <link href="https://linuxfr.org/users/epeios/liens/sortie-du-rpi-pico-2-w-version-du-rpi-pico-2-coeurs-arm-risc-v-equipe-du-wi-fi-et-du-bluetooth" />
        <id>https://linuxfr.org/users/epeios/liens/sortie-du-rpi-pico-2-w-version-du-rpi-pico-2-coeurs-arm-risc-v-equipe-du-wi-fi-et-du-bluetooth</id>
        <updated>2024-11-26T14:02:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.raspberrypi.com/news/raspberry-pi-pico-2-w-on-sale-now/">https://www.raspberrypi.com/news/raspberry-pi-pico-2-w-on-sale-now/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137436/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/epeios/liens/sortie-du-rpi-pico-2-w-version-du-rpi-pico-2-coeurs-arm-risc-v-equipe-du-wi-fi-et-du-bluetooth#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Claude SIMON</name>
        </author>
    </entry>
    <entry>
        <title>Tremplin MiXiT 2025</title>
        <link href="https://discuss.afpy.org/t/tremplin-mixit-2025/2385" />
        <id>https://discuss.afpy.org/t/tremplin-mixit-2025/2385</id>
        <updated>2024-11-25T11:06:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Hello tout le monde,</p>
<p>Le <a href="https://mixitconf.org/fr/">MiXiT</a> et <a href="https://craftsrecords.org/">CraftRecords</a> retravaillent ensemble pour l’édition 2025 du MiXiT et proposent un tremplin.</p>
<p>L’idée du tremplin est d’accompagner des personnes qui n’ont jamais fait de conférence ; de la formalisation du sujet à la prise de parole.</p>
<p>Cette année, uniquement des sujets techniques sont recherchés.</p>
<p>6 personnes sont sélectionnées et accompagnées. À l’issue de la période de coaching, un meetup est organisé et le public vote pour ses conférences préférées.<br/>
Les deux conférences ayant le plus de voix seront sélectionnées pour le MiXiT !</p>
<p>Si vous êtes sur Lyon ou alentours, n’hésitez pas à <a href="https://buff.ly/413p2o6">postuler</a> (en plus les coachs sont trop sympas <img alt=":stuck_out_tongue:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/stuck_out_tongue.png?v=12" title=":stuck_out_tongue:" width="20"/>)</p>
<p><img alt=":date:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/date.png?v=12" title=":date:" width="20"/> Date limite pour postuler : 22 décembre 2024<br/>
<img alt=":studio_microphone:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/studio_microphone.png?v=12" title=":studio_microphone:" width="20"/> Meetup de sélection : 26 mars 2024<br/>
<img alt=":muscle:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/muscle.png?v=12" title=":muscle:" width="20"/> Équipe de coachs : Léa Coston, Yann Bouvet, Houleymatou Baldé, Antoine Caron, <a class="mention" href="https://discuss.afpy.org/u/lize">@liZe</a> et moi-même<br/>
<img alt=":arrow_right:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/arrow_right.png?v=12" title=":arrow_right:" width="20"/> Formulaire d’inscription : <a class="inline-onebox" href="https://buff.ly/413p2o6">Inscription Tremplin Mixit 2025</a></p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/tremplin-mixit-2025/2385">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Afficher une fenêtre de notification depuis le shell</title>
        <link href="https://ascendances.wordpress.com/2024/11/25/afficher-une-fenetre-de-notification-depuis-le-shell/" />
        <id>https://ascendances.wordpress.com/2024/11/25/afficher-une-fenetre-de-notification-depuis-le-shell/</id>
        <updated>2024-11-25T09:05:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Plusieurs commandes permettent d’afficher une fenêtre de notification qui disparaît automatiquement. Voici quelques outils avec les fonctionnalités minimales. Chacun d’entre eux a des paramètres supplémentaires spécifiques.</p>
<h2 class="wp-block-heading">Notify-send</h2>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-notify-send.png"><img alt="" class="wp-image-2984" height="106" src="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-notify-send.png?w=529" width="529"/></a></figure>
<p>notify-send est disponible dans le paquet <code>libnotify-bin</code> (dans Debian et ses dérivées) et est probablement déjà installé. La capture montre le rendu avec Gnome. La commande :</p>
<p><code>$ notify-send "ici un titre" "ici le contenu"</code></p>
<h2 class="wp-block-heading">Zenity</h2>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-zenity.png"><img alt="" class="wp-image-2986" height="235" src="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-zenity.png?w=309" width="309"/></a></figure>
<p><a href="https://gitlab.gnome.org/GNOME/zenity">zenity</a> est basé sur GTK et permet l’affichage de différents types de fenêtre. Pour obtenir la fermeture automatique de la fenêtre, il faut ajouter un paramètre spécifique :</p>
<p><code>$ zenity --info --title="ici un titre" --text="ici un contenu" --timeout=5</code></p>
<h2 class="wp-block-heading">Kdialog</h2>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-kdialog.png"><img alt="Notification avec kdialog" class="wp-image-2983" height="95" src="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-kdialog.png?w=342" width="342"/></a></figure>
<p><a href="https://develop.kde.org/docs/administration/kdialog/">kdialog</a> fait partie de KDE. Le type <code>passivepopup</code> est une notification qui apparaît dans un coin du bureau et disparaît automatiquement :</p>
<p><code>$ kdialog <code>--passivepopup</code> --title "ici un titre" "ici un contenu"</code></p>
<h2 class="wp-block-heading">Xmessage</h2>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-xmessage.png"><img alt="" class="wp-image-2985" height="100" src="https://ascendances.wordpress.com/wp-content/uploads/2024/11/exemple-xmessage.png?w=135" width="135"/></a></figure>
<p><code>xmessage</code> fait partie d’outils fournis avec X11 (paquet <code>x11-utils</code> sous Debian et dérivées). Il doit être disponible à peu près partout mais, contrairement aux commandes citées précédemment, ne bénéficie pas de l’intégration avec le thème du bureau. En bref, ça fonctionne mais c’est moche.</p>
<p><code>$ xmessage -timeout 5 "ici un contenu"</code></p>
<h2 class="wp-block-heading">Versions utilisées</h2>
<p>Le rendu des captures d’écran peuvent différer selon la version des logiciels utilisés. Les captures ont été faites avec :</p>
<ul class="wp-block-list">
<li>Gnome 47</li>
<li>KDE Plasma 5.27</li>
<li>Zenity 4.0.2</li>
<li>Xmessage 1.0.7</li>
</ul>
            </div>
        </content>
        <author>
            <name>ascendances</name>
        </author>
    </entry>
    <entry>
        <title>affichage label</title>
        <link href="https://discuss.afpy.org/t/affichage-label/2380" />
        <id>https://discuss.afpy.org/t/affichage-label/2380</id>
        <updated>2024-11-23T10:11:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
voici la structure de mon programme:</p>
<pre><code class="lang-python">import modules
fen=Tk()
...
label1=Label(fen,text,...)
...
# lecture des @ sites web dans un fichier csv
# test si @ site valide
# affichage des erreurs (Labels)
fen.mainloop()
</code></pre>
<p>Je dois attendre la fin du programme pour afficher le label1 alors qu’il est au début du programme. Merci de m’expliquer pourquoi cela se passe ainsi.</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/affichage-label/2380">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>Django : Optimiser les performances pour la production</title>
        <link href="https://slimsaas.com/blog/django-scaling-performance" />
        <id>https://slimsaas.com/blog/django-scaling-performance</id>
        <updated>2024-11-22T15:17:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez les meilleures pratiques pour optimiser Django dans des environnements de production. Cet article explore des techniques pour améliorer les performances, gérer l’évolutivité, et garantir la stabilité de vos applications Django à grande échelle. De la gestion des bases de données aux stratégies de mise en cache, chaque aspect est couvert pour vous aider à tirer le meilleur parti de votre stack.</p>
<a href="https://news.humancoders.com/t/python/items/26459-django-optimiser-les-performances-pour-la-producti"><img src="https://images.unsplash.com/photo-1516110723075-c29d0b4e6cc1?q=80&amp;w=3135&amp;auto=format&amp;fit=crop&amp;ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"/></a><hr/><a href="https://news.humancoders.com/t/python/items/26459-django-optimiser-les-performances-pour-la-producti#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/26459-django-optimiser-les-performances-pour-la-producti">Django : Optimiser les performances pour la production</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Et hop, un nouvel exercice sur HackInScience : les carrés magiques</title>
        <link href="https://discuss.afpy.org/t/et-hop-un-nouvel-exercice-sur-hackinscience-les-carres-magiques/2373" />
        <id>https://discuss.afpy.org/t/et-hop-un-nouvel-exercice-sur-hackinscience-les-carres-magiques/2373</id>
        <updated>2024-11-18T10:10:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>TL;DR : <a class="inline-onebox" href="https://www.hackinscience.org/exercises/magic-square">HackInScience — Magic Square</a></p>
<p>La moulinette étant toute fraîche elle contient probablement encore des bugs, sois indulgent et n’hésite pas à me donner quelques retours (ou faire une PR, le code est là <a class="inline-onebox" href="https://framagit.org/hackinscience/hkis-exercises/-/tree/main/exercises/magic-square">exercises/magic-square · main · hackinscience / hkis-exercises · GitLab</a>).</p>
<p>Oui je sais j’avais déjà quelque chose autour des carrés magiques (<a class="inline-onebox" href="https://www.hackinscience.org/exercises/dirichlet-solver">HackInScience — Dirichlet solver</a>) mais celui-ci est beaucoup plus simple.</p>
<p>Inspiré d’un exercice de math donné en élémentaire à une de mes filles, quand j’ai vu l’exo (remplir un carré magique) ma première réaction a été « ça se script… » et ma 2ème « ahh bah ça fera un exo hackinscience » <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=12" title=":slight_smile:" width="20"/></p>
<p>Si vous avez des idées d’exos je prends !</p>
<p><small>11 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/et-hop-un-nouvel-exercice-sur-hackinscience-les-carres-magiques/2373">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Utilisation de pybind11</title>
        <link href="https://discuss.afpy.org/t/utilisation-de-pybind11/2372" />
        <id>https://discuss.afpy.org/t/utilisation-de-pybind11/2372</id>
        <updated>2024-11-17T20:08:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Coucou ici,</p>
<p>Je tente de générer un binding python pour une librairie. Pour le moment, je ne gère qu’une classe avec une seule méthode.</p>
<p>Mais quoi que je fasse, j’obtiens toujours une erreur “undefined symbol”.</p>
<p>Quelques infos :</p>
<ul>
<li>La librairie compile bien, en dynamique ou en statique.</li>
<li>j’ai réussi à générer les exemples donnés par pybind11 dans leur tutoriel (les premiers pas quoi)</li>
<li>la commande que j’utilise pour compiler est un poil complexe :</li>
</ul>
<p><code>g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) -ISFML/include -Lbuild/lib -lsfml-system pysfml2/example.cpp -o example$(python3-config --extension-suffix)</code></p>
<p>la librairie a été compilée dans le répertoire build/lib et son nom est libsfml-system.so ou bien libsfml-system-s (pour la version statique), mon fichier pybind11 est  pysfml2/main.cpp.</p>
<p>La compilation se passe bien, mais si j’importe le résultat :</p>
<pre><code class="lang-python">&gt;&gt;&gt; import example
ImportError: /[...]/sfml/example.cpython-312-x86_64-linux-gnu.so: undefined symbol: _ZNK2sf4Time9asSecondsEv
</code></pre>
<p>Il ne trouve donc ps le symbole sf::Time.asSeconds.</p>
<p>Tout idée est la bienvenue <img alt=":slight_smile:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/slight_smile.png?v=12" title=":slight_smile:" width="20"/></p>
<p><small>5 messages - 3 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/utilisation-de-pybind11/2372">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>Mindiell</name>
        </author>
    </entry>
    <entry>
        <title>Python dans org-mode avec des tables en entrée et en sortie</title>
        <link href="https://discuss.afpy.org/t/python-dans-org-mode-avec-des-tables-en-entree-et-en-sortie/2371" />
        <id>https://discuss.afpy.org/t/python-dans-org-mode-avec-des-tables-en-entree-et-en-sortie/2371</id>
        <updated>2024-11-17T16:02:51Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>On en parlait avec <a class="mention" href="https://discuss.afpy.org/u/merwyn">@Merwyn</a> pendant la PyConFR, mais une démo vaut mieux que démo^Wdes mots :</p>
<p>D’abord ça nécessite un peu de config :</p>
<pre><code class="lang-elisp">(org-babel-do-load-languages
 'org-babel-load-languages
 '((python . t)))
</code></pre>
<p>puis dans un fichier org :</p>
<pre><code class="lang-org">On définit d'abord une table (optionnel mais bon pour la démo)
et on la nomme :

#+tblname: tbl-hostnames
| Host     |
|----------|
| mdk.fr   |
| afpy.org |

Ensuite un peu de Python, qui prend (ou pas) la table en variable
d'entrée :

#+begin_src python :var hostnames=tbl-hostnames
  import subprocess

  pings = []
  for hostname, in hostnames:
      pings.append((hostname, subprocess.run(["ping", "-c1", hostname], stdout=subprocess.PIPE).stdout.decode().splitlines()[-1]))

  return pings
#+end_src

#+RESULTS:
| mdk.fr   | rtt min/avg/max/mdev = 4.698/4.698/4.698/0.000 ms |
| afpy.org | rtt min/avg/max/mdev = 2.951/2.951/2.951/0.000 ms |

Pour exécuter le code (et avoir le `#+RESULTS` qui apparaît tout seul)
c'est comme toujours dans org-mode: `C-c C-c`.
</code></pre>
<p>J’entends d’ici les gens râler sur ma virgule après <code>for hostname</code>, haha.</p>
<p>Bon pas besoin de sortir Python pour juste un ping :</p>
<pre><code class="lang-python"> | mdk.fr        | 36.251/36.251/36.251/0.000 ms |
 | afpy.org      | 20.700/20.700/20.700/0.000 ms |
 | deb2.afpy.org | 19.779/19.779/19.779/0.000 ms |
 | bbb.afpy.org  | 20.608/20.608/20.608/0.000 ms |
#+TBLFM: $2='(shell-command-to-string (concat "ping -c 1 " $1 " | tail -n 1 | cut -d= -f2 | tr -d '\n'"))
</code></pre>
<p>D’ici à lancer mes playbooks Ansible depuis org-mode y’a qu’un pas…</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/python-dans-org-mode-avec-des-tables-en-entree-et-en-sortie/2371">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>Documentation multi langue alabaster</title>
        <link href="https://discuss.afpy.org/t/documentation-multi-langue-alabaster/2370" />
        <id>https://discuss.afpy.org/t/documentation-multi-langue-alabaster/2370</id>
        <updated>2024-11-17T10:22:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,</p>
<p>J’essaie de faire une documentation qui contient plusieurs langues avec sphinx et le thème alabaster. j’arrive bien à générer chaque langue, mais je n’ai rien pour passer de l’une a l’autre. C’est soit je génère une langue, soit l’autre mais pas les deux en même temps.<br/>
Savez-vous comment ajouter un moyen de passer d’une langue a l’autre dans la documentation générée?<br/>
Merci</p>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/documentation-multi-langue-alabaster/2370">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>yabb85</name>
        </author>
    </entry>
    <entry>
        <title>Rapport de transparence de la PyConFR 2024</title>
        <link href="https://discuss.afpy.org/t/rapport-de-transparence-de-la-pyconfr-2024/2367" />
        <id>https://discuss.afpy.org/t/rapport-de-transparence-de-la-pyconfr-2024/2367</id>
        <updated>2024-11-14T11:31:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>PyCon France (PyConFR) est une conférence qui a lieu chaque année (sauf circonstances exceptionnelles) en France. Cette année, elle a eu lieu du <a href="https://www.pycon.fr/2024">31 octobre au 3 novembre à Strasbourg</a>, rassemblant des personnes de la communauté Python. Les participantes et participants à la conférence sont tenues de respecter ​le <a href="https://www.afpy.org/docs/charte">Code de Conduite</a> de l’Association Francophone Python, l’association qui organise l’événement.</p>
<p>Le but de ce document est d’améliorer l’accueil et la sécurité des participantes et participants ainsi que de donner aux organisateurs et organisatrices des indicateurs sur le comportement de la communauté. En effet, pour pouvoir entendre, il faut pouvoir écouter. C’est maintenant devenu une pratique courante, pour les organisations ayant un Code de Conduite, de publier un rapport de transparence suite à la tenue d’une conférence. C’est le but de ce document.</p>
<p><a href="https://git.afpy.org/AFPy/gestion/src/branch/master/compte_rendus_diversite/2024.pdf"> Télécharger le rapport en PDF (FR/EN)</a></p>
<p><small>2 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/rapport-de-transparence-de-la-pyconfr-2024/2367">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>De l’art de quitter Kubernetes : témoignages</title>
        <link href="https://bearstech.com/societe/blog/de-lart-de-quitter-kubernetes-temoignages" />
        <id>https://bearstech.com/societe/blog/de-lart-de-quitter-kubernetes-temoignages</id>
        <updated>2024-11-13T12:03:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>claitner</name>
        </author>
    </entry>
    <entry>
        <title>Sur Bordeaux − Meetup le 11 décembre</title>
        <link href="https://discuss.afpy.org/t/sur-bordeaux-meetup-le-11-decembre/2366" />
        <id>https://discuss.afpy.org/t/sur-bordeaux-meetup-le-11-decembre/2366</id>
        <updated>2024-11-13T11:45:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut,</p>
<p>Deuxième meetup de l’année au Node à <a class="hashtag-cooked" href="https://discuss.afpy.org/tag/bordeaux"><span class="hashtag-icon-placeholder"><svg class="fa d-icon d-icon-square-full svg-icon svg-node" xmlns="http://www.w3.org/2000/svg"><use></use></svg></span><span>bordeaux</span></a> <img alt=":partying_face:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/partying_face.png?v=12" title=":partying_face:" width="20"/></p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="32" src="https://secure.meetupstatic.com/next/images/general/favicon.ico" width="32"/>
<a href="https://www.meetup.com/py-bdx/events/304470904/" rel="noopener nofollow ugc" target="_blank">Meetup</a>
</header>
<article class="onebox-body">
<div class="aspect-image"><img class="thumbnail" height="343" src="https://secure.meetupstatic.com/photos/event/3/9/d/5/600_524594805.jpeg" width="600"/></div>
<h3><a href="https://www.meetup.com/py-bdx/events/304470904/" rel="noopener nofollow ugc" target="_blank">Bordeaux Python Meetup 2024.2, mer. 11 déc. 2024, 18:30   | Meetup</a></h3>
<p>Le meetup Python bordelais revient le **11 décembre** 2024 au **Node** en soirée avec 2 présentations :

* *à 19:00 : **Les floats : entre précision et chaos*** (Alexandre</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-bordeaux-meetup-le-11-decembre/2366/1">Bordeaux Python Meetup 2024.2</a></p>
<p>2024-12-11 18:30 (Europe/Paris) → 2024-12-11 20:30 (Europe/Paris)</p>
</div>
<p><small>10 messages - 5 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/sur-bordeaux-meetup-le-11-decembre/2366">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>yoan</name>
        </author>
    </entry>
    <entry>
        <title>Comment créer un cercle vertueux avec Docker ?</title>
        <link href="https://bearstech.com/societe/blog/comment-creer-un-cercle-vertueux-avec-docker" />
        <id>https://bearstech.com/societe/blog/comment-creer-un-cercle-vertueux-avec-docker</id>
        <updated>2024-11-13T10:36:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>emazurier</name>
        </author>
    </entry>
    <entry>
        <title>PyLadiesCon 2024 − 6 au 8 décembre</title>
        <link href="https://discuss.afpy.org/t/pyladiescon-2024-6-au-8-decembre/2365" />
        <id>https://discuss.afpy.org/t/pyladiescon-2024-6-au-8-decembre/2365</id>
        <updated>2024-11-12T14:12:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>La <a href="https://conference.pyladies.com/">conférence PyLadies</a> revient en 2024, du 6 au 8 décembre !</p>
<p>Comme l’édition précédente, l’évènement est multi-langues (anglais, espagnol, portugais…) et multi-timezones.</p>
<p>Un premier programme est <a href="https://conference.pyladies.com/schedule/">en ligne</a>.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/pyladiescon-2024-6-au-8-decembre/2365/1">PyLadiesCon</a></p>
<p>2024-12-06 19:00 (Europe/Paris) → 2024-12-07 20:30 (Europe/Paris)</p>
</div>
<p><small>4 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/pyladiescon-2024-6-au-8-decembre/2365">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Sur Lyon − Meetup le 21 novembre</title>
        <link href="https://discuss.afpy.org/t/sur-lyon-meetup-le-21-novembre/2364" />
        <id>https://discuss.afpy.org/t/sur-lyon-meetup-le-21-novembre/2364</id>
        <updated>2024-11-12T08:21:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Salut tout le monde,</p>
<p>On se retrouve jeudi 21 novembre pour un meetup de retours de la PyConFR !</p>
<p>Rdv dès 19h à Hévéa (métro Jean Macé) où l’on sera accueilli par <a href="https://gentilsnuages.fr/">Gentils Nuages</a> <img alt=":cloud:" class="emoji" height="20" src="https://discuss.afpy.org/images/emoji/twitter/cloud.png?v=12" title=":cloud:" width="20"/>.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-21-novembre/2364/1">Retours de la PyConFR 2024</a></p>
<p>2024-11-21 19:00 (Europe/Paris) → 2024-11-21 22:00 (Europe/Paris)</p>
</div>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/sur-lyon-meetup-le-21-novembre/2364">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>grewn0uille</name>
        </author>
    </entry>
    <entry>
        <title>Réunions du comité directeur 2024-2025</title>
        <link href="https://discuss.afpy.org/t/reunions-du-comite-directeur-2024-2025/2362" />
        <id>https://discuss.afpy.org/t/reunions-du-comite-directeur-2024-2025/2362</id>
        <updated>2024-11-08T15:26:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ceci est le sujet lié à la réunion récurrente du comité directeur.<br/>
Celle-ci a lieu chaque mois le 3ème mardi à 20h30.</p>
<p>Les compte-rendus de réunions sont publiés sur <a href="https://git.afpy.org/AFPy/gestion/src/branch/master/compte_rendus_cd">notre dépôt git</a> et le lien sera posté sur ce sujet après chaque réunion.</p>
<p>Vous pouvez utiliser ce sujet pour proposer des points à aborder lors d’une prochaine réunion : vous serez alors invité à la prochaine réunion pour venir discuter de ce point.<br/>
Ces réunions sont aussi accessibles à toute personne qui en ferait la demande auprès du comité.</p>
<div style="border: 1px solid #dedede;">
<p><a href="https://discuss.afpy.org/t/reunions-du-comite-directeur-2024-2025/2362/1">Réunion du comité directeur</a></p>
<p>2024-11-19 20:30 (Europe/Paris)</p>
</div>
<p><small>3 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/reunions-du-comite-directeur-2024-2025/2362">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Version d&#39;un programme AppImage</title>
        <link href="https://discuss.afpy.org/t/version-dun-programme-appimage/2359" />
        <id>https://discuss.afpy.org/t/version-dun-programme-appimage/2359</id>
        <updated>2024-11-06T14:43:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour,<br/>
je cherche via un script a connaitre la version d’un logiciel externe de type AppImage. Y-aurait-il un moyen pour le faire ?<br/>
Par exemple avec BalenaEtcher si je le lance je récupère un résultat (str) dans lequel il y a la version. J’ai essayé avec LibreOffice mais cela ne donne rien.<br/>
Une idée serait la bienvenue, …si c’est possible…</p>
<p><small>19 messages - 2 participant(e)s</small></p>
<p><a href="https://discuss.afpy.org/t/version-dun-programme-appimage/2359">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mapommfj</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113430446777507201" />
        <id>https://mamot.fr/@AFPy/113430446777507201</id>
        <updated>2024-11-05T12:54:20Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Thank you to everyone who came to <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a> 2024! <br/>We hope you had a good time.<br/>If you would like to give your feedback for any areas of improvement for future editions, do not hesitate to fill out this survey: <a href="https://thym.courtbouillon.org/5" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="">thym.courtbouillon.org/5</span><span class="invisible"></span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113430423036216083" />
        <id>https://mamot.fr/@AFPy/113430423036216083</id>
        <updated>2024-11-05T12:48:18Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Merci à toutes les personnes étant venues à la <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a> 2024 ! <br/>Nous espérons que vous avez passé un bon moment.<br/>Si vous souhaitez donner votre retour pour toute piste d'amélioration pour les prochaines éditions, n'hésitez pas à remplir ce sondage : <a href="https://thym.courtbouillon.org/5" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="">thym.courtbouillon.org/5</span><span class="invisible"></span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113414527170092565" />
        <id>https://mamot.fr/@AFPy/113414527170092565</id>
        <updated>2024-11-02T17:25:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>La 3ème journée de la PyconFr se termine. Il ne vous reste plus qu'une journée pour venir voir des conférences et des ateliers sur votre langage de programmation préféré :D</p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Le sprint de la traduction de la doc de Python commence !</title>
        <link href="https://discuss.afpy.org/t/le-sprint-de-la-traduction-de-la-doc-de-python-commence/2349" />
        <id>https://discuss.afpy.org/t/le-sprint-de-la-traduction-de-la-doc-de-python-commence/2349</id>
        <updated>2024-10-31T10:19:24Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>On est en salle C09, mais si tu n’es pas à la PyConFR on va avoir besoin de relecture de PR ici :</p>
<aside class="onebox allowlistedgeneric">
<header class="source">
<img class="site-icon" height="123" src="https://git.afpy.org/assets/img/favicon.svg" width="152"/>
<a href="https://git.afpy.org/AFPy/python-docs-fr/pulls" rel="noopener" target="_blank">Le Gitea de l'AFPy</a>
</header>
<article class="onebox-body">
<img class="thumbnail onebox-avatar" height="290" src="https://git.afpy.org/repo-avatars/28-8f4657a057e2a27b0ba618c10afa2f63" width="290"/>
<h3><a href="https://git.afpy.org/AFPy/python-docs-fr/pulls" rel="noopener" target="_blank">python-docs-fr</a></h3>
<p>Traduction de la documentation de Python en français.</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both;"></div>
</aside>
<p>(relecture de PR ou traductions d’ailleurs !)</p>
<p><small>1 message - 1 participant(e)</small></p>
<p><a href="https://discuss.afpy.org/t/le-sprint-de-la-traduction-de-la-doc-de-python-commence/2349">Lire le sujet en entier</a></p>
            </div>
        </content>
        <author>
            <name>mdk</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113401513101171895" />
        <id>https://mamot.fr/@AFPy/113401513101171895</id>
        <updated>2024-10-31T10:16:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113401485914077310" />
        <id>https://mamot.fr/@AFPy/113401485914077310</id>
        <updated>2024-10-31T10:09:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                La PyConFR 2024 démarre ce jeudi 31 octobre à Strasbourg, inscription obligatoire mais gratuite
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113395236034860489" />
        <id>https://mamot.fr/@AFPy/113395236034860489</id>
        <updated>2024-10-30T07:39:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113395234169088845" />
        <id>https://mamot.fr/@AFPy/113395234169088845</id>
        <updated>2024-10-30T07:39:18Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                la PyConFR 2024 se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Le thon c&#39;est bon. Mangez-en !</title>
        <link href="https://linuxfr.org/users/alimentaire/liens/le-thon-c-est-bon-mangez-en" />
        <id>https://linuxfr.org/users/alimentaire/liens/le-thon-c-est-bon-mangez-en</id>
        <updated>2024-10-29T06:52:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://bloomassociation.org/contamination-au-mercure-bloom-revele-un-scandale-de-sante-publique-dune-ampleur-inedite/">https://bloomassociation.org/contamination-au-mercure-bloom-revele-un-scandale-de-sante-publique-dune-ampleur-inedite/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137194/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/alimentaire/liens/le-thon-c-est-bon-mangez-en#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Voltairine</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113384792713271359" />
        <id>https://mamot.fr/@AFPy/113384792713271359</id>
        <updated>2024-10-28T11:23:54Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                AFPy neck strap for PyConFR edition
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113384787977712155" />
        <id>https://mamot.fr/@AFPy/113384787977712155</id>
        <updated>2024-10-28T11:22:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                tour-de-cou de l'AFPy pour la PyConFR
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113362588628159377" />
        <id>https://mamot.fr/@AFPy/113362588628159377</id>
        <updated>2024-10-24T14:17:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                t-shirt pour la PyConFR 2024 à Strasbourg, t-shirt noir avec un logo sur le haut représentant un serpent rouge enroulé comme un bretzel, en-dessous se trouve les informations "PyConFR - 2024 Strasbourg"
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113344852099189445" />
        <id>https://mamot.fr/@AFPy/113344852099189445</id>
        <updated>2024-10-21T11:06:29Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Only 10 days to go until the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113344850351281371" />
        <id>https://mamot.fr/@AFPy/113344850351281371</id>
        <updated>2024-10-21T11:06:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Plus que 10 jours avant la PyConFR 2024, se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Un jeu vidéo en encart de Jeux et Stratégies : Le Sceptre Maudit v0.2</title>
        <link href="https://linuxfr.org/users/jlaumonier/journaux/un-jeu-video-en-encart-de-jeux-et-strategies-le-sceptre-maudit-v0-2" />
        <id>https://linuxfr.org/users/jlaumonier/journaux/un-jeu-video-en-encart-de-jeux-et-strategies-le-sceptre-maudit-v0-2</id>
        <updated>2024-10-20T13:57:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2 id="toc-doù-ça-vient">D'où ça vient ?</h2>
<p>Depuis un temps certain, je souhaite programmer des jeux vidéos. Un de mes plus vieux exemples est un (début de) jeu que j'avais appelé Sorciers et Sortilèges et que j'avais programmé en Basic.</p>
<p><img alt="sets-basic.gif" src="https://img.linuxfr.org/img/687474703a2f2f72656c656173652e6a656c796e65742e636f6d2f736574732d62617369632e676966/sets-basic.gif" title="Source : http://release.jelynet.com/sets-basic.gif"/></p>
<p>Je n'ai jamais terminé ce jeu pour des raisons techniques de gestion de mémoire, mais surtout parce que je n'avais aucune idée de ce que je voulais réaliser. Bref, à titre d'archive, ce jeu est disponible sous licence CC BY-SA 4.0 si quelqu'un est intéressé à y jeter un oeil : <a href="https://gitlab.com/jlaumonier/sets-qb.git">https://gitlab.com/jlaumonier/sets-qb.git</a></p>
<h2 id="toc-implémenter-un-jeu--le-sceptre-maudit">Implémenter un jeu : le Sceptre Maudit</h2>
<p>Mais ce n'est pas pour ça que je fais cette annonce aujourd'hui. En fait, comme je n'ai pas arrêté d'essayer de programmer des jeux, je me suis pour l'instant réorienté vers la réimplémentation de jeux existants, et principalement des jeux de plateau. Ça me permet de me concentrer sur la partie technique pour la base et en parallèle, je pense à quelle sorte de jeu je veux vraiment faire.</p>
<p>Donc, je me suis mis au Python et j'ai commencé par "Le Sceptre Maudit" provenant du <a href="https://www.abandonware-magazines.org/affiche_mag.php?mag=185">Jeux et Stratégies</a> no 38 et je sors aujourd'hui la version 0.2. Cette version permet de créer un personnage, de se déplacer sur le plateau et d'ouvrir/casser des portes. Il permet aussi de jouer à plusieurs via un réseau local.</p>
<p><strong>À 1 seul joueur :</strong><br/>
<img alt="sceptremaudit-v0.2-solo.gif" src="https://img.linuxfr.org/img/687474703a2f2f72656c656173652e6a656c796e65742e636f6d2f736365707472656d61756469742d76302e322d736f6c6f2e676966/sceptremaudit-v0.2-solo.gif" title="Source : http://release.jelynet.com/sceptremaudit-v0.2-solo.gif"/></p>
<p><strong>Et à plusieurs :</strong><br/>
<img alt="sceptremaudit-v0.2-2players.gif" src="https://img.linuxfr.org/img/687474703a2f2f72656c656173652e6a656c796e65742e636f6d2f736365707472656d61756469742d76302e322d32706c61796572732e676966/sceptremaudit-v0.2-2players.gif" title="Source : http://release.jelynet.com/sceptremaudit-v0.2-2players.gif"/></p>
<p>La version 0.2 est disponible pour linux et win64 : <a href="https://gitlab.com/jlaumonier/encartgames/-/releases/v0.2">https://gitlab.com/jlaumonier/encartgames/-/releases/v0.2</a>. Le code source est disponible sous licence CC BY-SA-NC 4.0 sur gitlab : <a href="https://gitlab.com/jlaumonier/encartgames.git">https://gitlab.com/jlaumonier/encartgames.git</a></p>
<h2 id="toc-py-mas-engine-plateform">Py MAS Engine Plateform</h2>
<p>Ce jeu est basé sur une bibliothèque multiagent, que je développe en parallèle, Pymasep (qui vient de sortir en version 0.2 aussi), et que je n'ose pas vraiment appeler un moteur de jeu, mais que je ne sais pas vraiment comment classer. C'est un mélange entre moteur de simulation et moteur de jeu, mais sans avoir totalement les caractéristiques propres à chacun. </p>
<p>Sans trop rentrer dans les détails, cette bibliothèque vise à utiliser des concepts le plus près possible des véritables concepts des jeux en général, un peu à la manière d'une <a href="https://en.wikipedia.org/wiki/Domain-driven_design">architecture orientée domaine</a> et bien sûr avec une <a href="https://fr.wikipedia.org/wiki/Architecture_orient%C3%A9e_agents">architecture orientée agents</a>. Pour cela, elle s'appuie sur des modèles théoriques comme le <a href="https://en.wikipedia.org/wiki/Decentralized_partially_observable_Markov_decision_process">DEC-POMDP</a> et les <a href="https://en.wikipedia.org/wiki/Conceptual_graph">Graphes conceptuels</a>. D'un point de vue technique, elle est basée sur pygame-ce et pygame-gui pour la partie affichage.</p>
<p>Elle est disponible comme paquet pypi et sur gitlab sous license MIT :</p>
<p><a href="https://pypi.org/project/pymasep/">https://pypi.org/project/pymasep/</a></p>
<p><a href="https://readthedocs.org/projects/pymasep/">https://readthedocs.org/projects/pymasep/</a></p>
<p><a href="https://gitlab.com/jlaumonier/pymasep">https://gitlab.com/jlaumonier/pymasep</a></p>
<p>Pour un exemple d'utilisation de Pymasep avec une implémentation simple de l'algorithme Q-Learning sur le jeu de Chat et Souris : <a href="https://gitlab.com/jlaumonier/pymasep-examples">https://gitlab.com/jlaumonier/pymasep-examples</a></p>
<p><img alt="Cat/Mouse Qlearning" src="https://img.linuxfr.org/img/687474703a2f2f72656c656173652e6a656c796e65742e636f6d2f70796d617365702d6578616d706c652e676966/pymasep-example.gif" title="Source : http://release.jelynet.com/pymasep-example.gif"/></p>
<p>Si vous trouvez ça intéressant, faites-moi signe, ça m'indiquera à quel point je continuerai les annonces des nouvelles sorties. Aussi, si vous connaissez des communautés sur Internet qul pourraient être intéressées, dites-le-moi ou n'hésitez pas à partager l'annonce.</p>
<div><a href="https://linuxfr.org/users/jlaumonier/journaux/un-jeu-video-en-encart-de-jeux-et-strategies-le-sceptre-maudit-v0-2.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137092/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/jlaumonier/journaux/un-jeu-video-en-encart-de-jeux-et-strategies-le-sceptre-maudit-v0-2#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Julien Laumonier</name>
        </author>
    </entry>
    <entry>
        <title>Comparaison de la scalabilité horizontale et verticale pour la mise à l&#39;échelle de vos applications</title>
        <link href="https://bearstech.com/societe/blog/comparaison-de-la-scalabilite-horizontale-et-verticale-pour-la-mise-lechelle-de-vos" />
        <id>https://bearstech.com/societe/blog/comparaison-de-la-scalabilite-horizontale-et-verticale-pour-la-mise-lechelle-de-vos</id>
        <updated>2024-10-19T21:35:03Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>Ce que j&#39;ai appris en créant le backend Python pour YTO</title>
        <link href="https://youtubetranscriptoptimizer.com/blog/02_what_i_learned_making_the_python_backend_for_yto" />
        <id>https://youtubetranscriptoptimizer.com/blog/02_what_i_learned_making_the_python_backend_for_yto</id>
        <updated>2024-10-18T09:10:43Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article explore les leçons tirées de la création du backend Python pour YouTube Transcript Optimizer (YTO). L’auteur partage des réflexions sur la conception de l’architecture, l’optimisation des performances, la gestion des erreurs et les défis rencontrés lors du développement. Il offre des conseils pratiques pour les développeurs cherchant à créer des services backend efficaces et bien structurés.</p>
<a href="https://news.humancoders.com/t/python/items/25304-ce-que-j-ai-appris-en-creant-le-backend-python-pou"><img src="https://raw.githubusercontent.com/Dicklesworthstone/yto_blog_posts/refs/heads/main/blog_02_banner.webp"/></a><hr/><a href="https://news.humancoders.com/t/python/items/25304-ce-que-j-ai-appris-en-creant-le-backend-python-pou#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/25304-ce-que-j-ai-appris-en-creant-le-backend-python-pou">Ce que j'ai appris en créant le backend Python pour YTO</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Matthieu Segret</name>
        </author>
    </entry>
    <entry>
        <title>Comparaison des performances : Python 3.12 vs Python 3.13</title>
        <link href="https://en.lewoniewski.info/2024/python-3-12-vs-python-3-13-performance-testing/" />
        <id>https://en.lewoniewski.info/2024/python-3-12-vs-python-3-13-performance-testing/</id>
        <updated>2024-10-18T08:07:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article examine les différences de performances entre Python 3.12 et Python 3.13 à travers divers tests et benchmarks. L’auteur compare la vitesse d’exécution, l’efficacité mémoire, et d’autres métriques clés pour évaluer les améliorations apportées par la nouvelle version. Il met également en lumière les nouveaux ajustements internes du langage qui impactent les performances des applications Python dans différents contextes.
All tests were run o</p>
<a href="https://news.humancoders.com/t/python/items/25238-comparaison-des-performances-python-3-12-vs-python"><img src="https://en.lewoniewski.info/uploads/2024/10/python313.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/25238-comparaison-des-performances-python-3-12-vs-python#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/25238-comparaison-des-performances-python-3-12-vs-python">Comparaison des performances : Python 3.12 vs Python 3.13</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113322195301654009" />
        <id>https://mamot.fr/@AFPy/113322195301654009</id>
        <updated>2024-10-17T11:04:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>🇬🇧  Saturday November 2 at <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a>, join us for the <a class="mention hashtag" href="https://mamot.fr/tags/PyLadies" rel="tag">#<span>PyLadies</span></a> luncheon!🍽️ <br/>It's free, but registration is required. <br/>Don't miss this opportunity to meet other Python enthusiasts! </p><p>Details and registration: <a href="https://lstu.fr/x7XYt0hm" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="">lstu.fr/x7XYt0hm</span><span class="invisible"></span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113322193647007816" />
        <id>https://mamot.fr/@AFPy/113322193647007816</id>
        <updated>2024-10-17T11:04:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>🇫🇷  Samedi 2 novembre à la <a class="mention hashtag" href="https://mamot.fr/tags/PyConFR" rel="tag">#<span>PyConFR</span></a>, rejoignez-nous pour le déjeuner des <a class="mention hashtag" href="https://mamot.fr/tags/PyLadies" rel="tag">#<span>PyLadies</span></a> !🍽️ <br/>Un moment convivial et gratuit, mais l'inscription est obligatoire. <br/>Ne manquez pas cette occasion de rencontrer d'autres passionnées de Python ! </p><p>Détails et inscription : <a href="https://lstu.fr/x7XYt0hm" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="">lstu.fr/x7XYt0hm</span><span class="invisible"></span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Dernières nouvelles de FPDF2</title>
        <link href="https://chezsoi.org/lucas/blog/fpdf2-latest-news.html" />
        <id>https://chezsoi.org/lucas/blog/fpdf2-latest-news.html</id>
        <updated>2024-10-15T10:29:04Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article présente les dernières mises à jour de FPDF2, une bibliothèque Python pour la génération de fichiers PDF. Il détaille les nouvelles fonctionnalités, les corrections de bugs et les améliorations de performance, ainsi que les contributions récentes de la communauté. FPDF2 continue d’évoluer avec des ajouts comme la prise en charge de nouvelles polices et des outils pour faciliter la création de documents PDF personnalisés.</p>
<a href="https://news.humancoders.com/t/python/items/25139-dernieres-nouvelles-de-fpdf2"><img src="https://chezsoi.org/lucas/blog/images/2024/10/MyGodItsFullOfStars.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/25139-dernieres-nouvelles-de-fpdf2#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/25139-dernieres-nouvelles-de-fpdf2">Dernières nouvelles de FPDF2</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Lucas-C</name>
        </author>
    </entry>
    <entry>
        <title>Le « build in public » Algoo de la semaine 41/2024</title>
        <link href="https://linuxfr.org/users/lebouquetin/liens/le-build-in-public-algoo-de-la-semaine-41-2024" />
        <id>https://linuxfr.org/users/lebouquetin/liens/le-build-in-public-algoo-de-la-semaine-41-2024</id>
        <updated>2024-10-15T10:25:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.algoo.fr/fr/actualites/article/le-build-in-public-algoo-de-la-semaine-41-2024">https://www.algoo.fr/fr/actualites/article/le-build-in-public-algoo-de-la-semaine-41-2024</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/137033/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/lebouquetin/liens/le-build-in-public-algoo-de-la-semaine-41-2024#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>LeBouquetin</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113305438084198946" />
        <id>https://mamot.fr/@AFPy/113305438084198946</id>
        <updated>2024-10-14T12:02:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Only 17 days to go until the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113305436260573434" />
        <id>https://mamot.fr/@AFPy/113305436260573434</id>
        <updated>2024-10-14T12:02:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Plus que 17 jours avant la PyConFR 2024, se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>écrire du code dans le corps d&#39;une classe python</title>
        <link href="https://linuxfr.org/users/killruana/journaux/ecrire-du-code-dans-le-corps-d-une-classe-python" />
        <id>https://linuxfr.org/users/killruana/journaux/ecrire-du-code-dans-le-corps-d-une-classe-python</id>
        <updated>2024-10-11T16:32:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découverte que je viens de faire à l'instant : il est possible d'écrire du code dans le corps d'une classe python, et ce code est exécuté automatiquement au chargement du module.</p>
<p>Exemple :</p>
<pre><code class="python3"><span class="kn">import</span> <span class="nn">datetime</span>

<span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">isoweekday</span><span class="p">()</span> <span class="o">==</span> <span class="mi">5</span><span class="p">:</span>
        <span class="n">current_day</span> <span class="o">=</span> <span class="s2">"trolldi"</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
            <span class="nb">print</span><span class="p">(</span><span class="s2">"TODAY IS"</span><span class="p">,</span> <span class="n">current_day</span><span class="p">,</span> <span class="s2">"!!!!!!!!"</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">current_day</span> <span class="o">=</span> <span class="s2">"pas trolldi"</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">"current_day:"</span><span class="p">,</span> <span class="n">MyClass</span><span class="o">.</span><span class="n">current_day</span><span class="p">)</span></code></pre>
<pre><code class="shell">$ python3 bla.py
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
TODAY IS trolldi !!!!!!!!
current_day: trolldi</code></pre>
<p>Voila, c'est tout. Bisous et bon weekend à tous !</p>
<div><a href="https://linuxfr.org/users/killruana/journaux/ecrire-du-code-dans-le-corps-d-une-classe-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/136998/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/killruana/journaux/ecrire-du-code-dans-le-corps-d-une-classe-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>jtremesay</name>
        </author>
    </entry>
    <entry>
        <title>Alexandre Astier code en Python</title>
        <link href="https://linuxfr.org/users/rewind/journaux/alexandre-astier-code-en-python" />
        <id>https://linuxfr.org/users/rewind/journaux/alexandre-astier-code-en-python</id>
        <updated>2024-10-10T20:48:37Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Lors d'une interview qu'il a donné à la chaîne Youtube Legend, Alexandre Astier répond à une série de rumeurs le concernant. Une de ces rumeurs est : «Tu envoies toi-même tes courriers recommandés quand c'est les scénarios pour fermer toi-même l'enveloppe et les amener à la Poste». Ce à quoi il répond : «Tellement pas ! C'est complètement faux. Il n'y a pas de courrier, il n'y a pas de version papier, je code mes PDF et les PDF sont mis sur un serveur avec un autre code et une autre interface qui est générée par une appli Python que j'ai écrite moi-même. Les mecs, je les attends»</p>
<p>Il sait vraiment tout faire ce gars, c'est assez exceptionnel.</p>
<div><a href="https://linuxfr.org/users/rewind/journaux/alexandre-astier-code-en-python.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/136991/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/rewind/journaux/alexandre-astier-code-en-python#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>rewind</name>
        </author>
    </entry>
    <entry>
        <title>Nouveautés de Python 3.13</title>
        <link href="https://docs.python.org/3.13/whatsnew/3.13.html" />
        <id>https://docs.python.org/3.13/whatsnew/3.13.html</id>
        <updated>2024-10-09T10:33:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>La version 3.13 de Python apporte des améliorations majeures, dont la désactivation possible du Global Interpreter Lock (GIL) pour un multi-threading optimisé et l’intégration du compilateur Just-in-Time (JIT). Ces nouveautés améliorent les performances et la gestion des threads, offrant aux développeurs des gains d’efficacité notables. D’autres optimisations et corrections rendent cette version essentielle pour les utilisateurs de Python.</p>
<a href="https://news.humancoders.com/t/python/items/24941-nouveautes-de-python-3-13"><img src="https://docs.python.org/3/_static/og-image.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/24941-nouveautes-de-python-3-13#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/24941-nouveautes-de-python-3-13">Nouveautés de Python 3.13</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Matthieu Segret</name>
        </author>
    </entry>
    <entry>
        <title>Mon équipe idéale</title>
        <link href="https://dmerej.info/blog/fr/post/mon-%C3%A9quipe-id%C3%A9ale/" />
        <id>https://dmerej.info/blog/fr/post/mon-%C3%A9quipe-id%C3%A9ale/</id>
        <updated>2024-10-08T11:29:35Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1 id="introduction">Introduction <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#introduction">#</a></h1>
<h2 id="3nbspans-chez-arolla--un-bilan">3 ans chez Arolla : un bilan <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#3nbspans-chez-arolla--un-bilan">#</a></h2>
<p>Le 18 octobre 2024 cela fera trois ans exactement que j’aurai rejoint
Arolla - une ESN à Paris où j’aurai beaucoup appris, et
aussi beaucoup transmis, en tout cas c’est ce que j’espère.</p>
<p>J’ai par exemple eu l’opportunité de découvrir le métier de coach, en
accompagnant une dizaine d’équipes sur des sujets divers et dans des
contextes variés, et même effectué une courte mission de conseil avec le
CTO d’Arolla, Cyrille Martraire.</p>
<p>Au final, j’ai rencontré beaucoup de monde, que ce soit les autres
consultants et consultantes d’Arolla, les équipes que j’ai rejointes
pour des missions de développement ou de coaching, et enfin toutes les
personnes que j’ai formées. Ces rencontres ont souvent été extrêmement
enrichissantes.</p>
<p>J’en profite pour remercier ici celles et ceux avec qui j’ai pu avoir
des discussions passionnantes et qui m’ont également aidé et soutenu
quand j’en avais besoin - j’espère avoir pu vous aider en retour.</p>
<h2 id="à-la-recherche-dun-nouvel-emploi">À la recherche d’un nouvel emploi <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#%c3%a0-la-recherche-dun-nouvel-emploi">#</a></h2>
<p>Malheureusement, toutes les bonnes choses ont une fin et, mon contrat avec Arolla se terminant
bientôt, je me retrouve depuis la semaine dernière sur le marché du travail.</p>
<p>Celles et ceux qui me connaissent savent que je préfère par-dessus tout travailler dans une équipe
où je me sens bien, et que rien ne me plaît davantage que de résoudre des problèmes complexes
à plusieurs.</p>
<p>Ainsi, au-delà des aspects pratiques (le lieu géographique, le domaine
d’activité, le salaire, etc.), ce sont bien les caractéristiques de
l’équipe que je serais amené à rejoindre qui vont être déterminantes
dans le choix de mon prochain poste, et je vais tenter de les détailler
ici.</p>
<h1 id="mon-équipe-idéale">Mon équipe idéale <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#mon-%c3%a9quipe-id%c3%a9ale">#</a></h1>
<p>D’abord, elle assure la sécurité psychologique des personnes qui la compose:</p>
<ul>
<li>La santé et le bien-être des membres de l’équipe (et de leurs proches) passent toujours avant les
considérations commerciales ou financières.</li>
<li>L’equipe dispose d’un code de conduite clair (notamment sur les blagues déplacées),
de personnes qu’on peut contacter si l’on se sent mal à l’aise, et
d’un dispositif pour prendre des sanctions rapides le cas échéant si jamais le code
de conduite n’est pas respecté.</li>
<li>Elle prend le temps de bien faire les choses bien plutôt que de subir des pressions
et de prendre des raccourcis.</li>
<li>Les personnes qui la composent prennent soin les unes des autres.</li>
</ul>
<p>Ensuite, elle se repose sur l’intelligence collective :</p>
<ul>
<li>Elle utilise une communication douce et positive, à la fois entre les membres et avec les autres équipes autour d’elle</li>
<li>Elle pratique la recherche du consensus et une certaine forme de démocratie interne</li>
<li>Elle cultive une atmosphère où les erreurs sont perçues comme des occasions d’apprendre
plutôt que des échecs qui doivent être sanctionnés.</li>
<li>Ses membres travaillent régulièrement à plusieurs, que ce soit en binôme
ou par petits groupes.</li>
<li>Elle se retrouve régulièrement (en présentiel de préférence) pour prendre de la
hauteur sur ses méthodes de travail et ses outils - et trouver des
solutions concrètes pour améliorer le quotidien de ses membres.</li>
</ul>
<p>Enfin, elle est composée de personnes diverses et variées. Ces différences sont respectées et sont une source
de réflexion et de partage.</p>
<p>Côté code (parce que je compte bien continuer à développer 😉 ) :</p>
<ul>
<li>Les postes de travail sont agréables à utiliser, sans restrictions inutiles.</li>
<li>L’équipe emploie déjà des méthodes Craft (telles que le TDD, le pair
programming, ou la programmation à plusieurs) - ou est volontaire pour
les découvrir et les mettre en place au quotidien.</li>
<li>L’équipe travaille dans en domaine riche en complexité métier - et elle peut discuter
facilement avec les utilisateurs finaux des applications qu’elle développe.</li>
<li>Enfin, elle utilise un langage que j’apprécie (ça peut aller de Rust à
Python en passant par Java et TypeScript) - dans un contexte où je
suis compétent (le backend d’applications web, ou les outils en ligne
de commande). Cela dit je suis ouvert à l’exploration d’autres contextes.</li>
</ul>
<h1 id="conclusion">Conclusion <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusion">#</a></h1>
<p>Je ne sais pas si une telle équipe existe : j’en ai croisé quelques-unes
qui y ressemblaient beaucoup - et je pense avoir pu contribuer
modestement à faire progresser celles dans lesquelles je me trouvais
dans la bonne direction. Je pense aussi que dans les bonnes conditions,
cet idéal est non seulement souhaitable mais atteignable.</p>
<p>Si vous partagez cette vision - et encore plus si vous connaissez une
équipe proche de celle que j’ai décrite (et qui recrute à Paris ou pas loin) - alors
faites-moi signe (dans les commentaires ou via ma
<a href="https://dmerej.info/blog/fr/pages/about/">page de contact</a>) - et n’hésitez pas à relayer cet article
autour de vous.</p>
<p>Sinon, si cette vision vous semble trop idéaliste, alors le prendrai
comme un compliment 😎.</p>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113271157784951343" />
        <id>https://mamot.fr/@AFPy/113271157784951343</id>
        <updated>2024-10-08T10:45:03Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Avis aux entreprises qui voudraient sponsoriser en dernières minutes : il n'est pas trop tard. </p><p><a href="https://www.pycon.fr/2024/fr/sponsors.html" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://www.</span><span class="">pycon.fr/2024/fr/sponsors.html</span><span class="invisible"></span></a></p>
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Python 3.13.0 — première version avec un mode expérimental supprimant le verrou global !</title>
        <link href="https://linuxfr.org/users/thoasm/liens/sortie-de-python-3-13-0-premiere-version-avec-un-mode-experimental-supprimant-le-verrou-global" />
        <id>https://linuxfr.org/users/thoasm/liens/sortie-de-python-3-13-0-premiere-version-avec-un-mode-experimental-supprimant-le-verrou-global</id>
        <updated>2024-10-07T20:58:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <a href="https://www.python.org/downloads/release/python-3130/">https://www.python.org/downloads/release/python-3130/</a> <p>
<strong>Commentaires :</strong>
<a href="https://linuxfr.org/nodes/136954/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/thoasm/liens/sortie-de-python-3-13-0-premiere-version-avec-un-mode-experimental-supprimant-le-verrou-global#comments">ouvrir dans le navigateur</a>
</p>
            </div>
        </content>
        <author>
            <name>Thomas Douillard</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113265700170026647" />
        <id>https://mamot.fr/@AFPy/113265700170026647</id>
        <updated>2024-10-07T11:37:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Only 24 days to go until the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113265698410588441" />
        <id>https://mamot.fr/@AFPy/113265698410588441</id>
        <updated>2024-10-07T11:36:40Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Plus que 24 jours avant la PyConFR 2024, se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Des bases de données en Python avec sqlite3</title>
        <link href="https://zestedesavoir.com/tutoriels/1294/des-bases-de-donnees-en-python-avec-sqlite3/" />
        <id>https://zestedesavoir.com/tutoriels/1294/des-bases-de-donnees-en-python-avec-sqlite3/</id>
        <updated>2024-10-05T15:46:53Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Comment stocker pour mieux régner
            </div>
        </content>
        <author>
            <name>Vk</name>
        </author>
    </entry>
    <entry>
        <title>Tout ce que vous devez savoir sur Python 3.13 – JIT et suppression du GIL</title>
        <link href="https://drew.silcock.dev/blog/everything-you-need-to-know-about-python-3-13/" />
        <id>https://drew.silcock.dev/blog/everything-you-need-to-know-about-python-3-13/</id>
        <updated>2024-10-01T14:59:22Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article présente les deux grandes innovations de Python 3.13 : la possibilité de désactiver le Global Interpreter Lock (GIL) pour un multi-threading plus efficace et l’introduction du Just-in-Time (JIT) compiler pour des performances accrues. Il détaille les implications de ces changements pour les développeurs, en particulier en ce qui concerne les performances des tâches lourdes en calcul.</p>
<a href="https://news.humancoders.com/t/python/items/24779-tout-ce-que-vous-devez-savoir-sur-python-3-13-jit"><img src="https://drew.silcock.dev/open-graph/blog/everything-you-need-to-know-about-python-3-13.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/24779-tout-ce-que-vous-devez-savoir-sur-python-3-13-jit#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/24779-tout-ce-que-vous-devez-savoir-sur-python-3-13-jit">Tout ce que vous devez savoir sur Python 3.13 – JIT et suppression du GIL</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Matthieu Segret</name>
        </author>
    </entry>
    <entry>
        <title>Écrire des scénarios de test de charge performants : le guide étape par étape</title>
        <link href="https://bearstech.com/blog/ecrire-des-scenarios-de-test-de-charge-performants-le-guide-etape-par-etape" />
        <id>https://bearstech.com/blog/ecrire-des-scenarios-de-test-de-charge-performants-le-guide-etape-par-etape</id>
        <updated>2024-09-30T15:06:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>AFPy</title>
        <link href="https://mamot.fr/@AFPy/113226380832316513" />
        <id>https://mamot.fr/@AFPy/113226380832316513</id>
        <updated>2024-09-30T12:57:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Only 31 days to go until the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.
            </div>
        </content>
        <author>
            <name>AFPy - Mastodon</name>
        </author>
    </entry>
    <entry>
        <title>Introduction à l&#39;UX, présentation d&#39;une présentation</title>
        <link href="https://yaal.coop/blog/sensibilisation-ux" />
        <id>https://yaal.coop/blog/sensibilisation-ux</id>
        <updated>2024-09-22T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Expérience utilisateur, sensibilisation et périmètre</h1>
<p>Etant l'unique designer de l'équipe de Yaal Coop à ce jour et depuis l'ouverture de la SCIC en 2020, j'ai réalisé courant 2023 une petite présentation de sensibilisation à l'UX, ou Expérience Utilisateur, à destination du reste de l'équipe.</p>
<p>On trouvait ça dommage de tout garder pour nous, alors c'est accessible à tous⋅tes !</p>
<p>La présentation, en format pages web, est accessible à tous⋅tes sur notre site à l'adresse <a href="https://yaal.coop/ux/index.html">https://yaal.coop/ux/index.html</a>.
Elle regroupe quelques notions de base d'UX, comme son périmètre, son interconnexion avec les métiers adjacents (conception, développement, communication, support...), quelques éléments sur lesquels être vigilants à chaque étape de conception, et quelques outils pratiques d'expérience utilisateur et de design.</p>
<p>La vision proposée dans cette courte présentation survole un sujet vaste et qui mérite beaucoup plus d'heures et d'assiduité pour connaître tous ses rouages. J'espère qu'elle peut inspirer des développeurs et développeuses à s'y pencher plus en profondeur !</p>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Summer 2024 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2024" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2024</id>
        <updated>2024-09-21T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://pygments.org/">Pygments</a></h2>
<p><em>Pygments is a generic syntax highlighter written in Python</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/2757">Add Changed-By field to debian control lexer</a></li>
<li><a href="https://github.com/pygments/pygments/pull/2767">Fix parsing in quoted string containing comment character</a> in IniLexer lexer</li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Collection of tools and libraries written for Sony's Playstation Portable (PSP) gaming console</em></p>
<ul>
<li>Documentation improvement: <a href="https://github.com/pspdev/pspsdk/pull/234">fix a link to the licence</a>, <a href="https://github.com/pspdev/pspsdk/pull/235">delete an obsolete README file</a> and <a href="https://github.com/pspdev/pspsdk/pull/236">fix typos</a></li>
</ul>
<h2>apt-setup</h2>
<p><em>Part of Debian-Installer. Generate an /etc/apt/sources.list for the installed system</em></p>
<ul>
<li>Documentation improvement: <a href="https://salsa.debian.org/installer-team/apt-setup/-/merge_requests/18">catch up the current behavior of 01setup</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/35">Dynamic models from schemas</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/38">Support for models with multiple extensions</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/40">Models to schemas export support</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/41">Fix attributes case sensitivity</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/44">Extensions use pydantic fields</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/47">Fix attributes case sensitivity</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/52"><code>ListResponse</code> schema order fixes</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/65">Typing fixes</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/66">Use type parameters for <code>ListResponse</code></a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/67">Typing fixes</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/68">Unit test warnings fixes</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/69">Extension mechanism rework</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/71">Downstream projects unit tests CI</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/76">Pydantic discriminator warning fix</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/78">Extension payloads are optional</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-client">scim2-client</a></h2>
<p><em>Pythonically build SCIM requests and parse SCIM responses</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-client/pull/20"><code>Content-Type</code> header charset support</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-tester">scim2-tester</a></h2>
<p><em>SCIM RFCs server compliance checker</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-tester/pull/5">Usage documentation</a></li>
<li><a href="https://github.com/yaal-coop/scim2-tester/pull/7">Fix network errors handling</a></li>
<li><a href="https://github.com/yaal-coop/scim2-tester/pull/9">Compatibility with scim2-client 0.2.0</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-cli">scim2-cli</a></h2>
<p><em>SCIM application development CLI</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-cli/pull/7">Dynamic command parameters</a></li>
<li><a href="https://github.com/yaal-coop/scim2-cli/pull/10">Binaries building documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-server">scim2-server</a></h2>
<p><em>Lightweight SCIM2 server prototype</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-server/pull/3"><code>/v2</code> prefix is optional</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Identity and Access management library for python</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/676">GHA action update</a></li>
</ul>
<h2><a href="https://github.com/element-hq/synapse">synapse</a></h2>
<p><em>Matrix homeserver written in Python/Twisted</em></p>
<ul>
<li><a href="https://github.com/element-hq/synapse/pull/17667">Pydantic import refactoring</a></li>
</ul>
<h2><a href="https://felix-martel.github.io/pydanclick">pydanclick</a></h2>
<p>*Add click options from a Pydantic model *</p>
<ul>
<li><a href="https://github.com/felix-martel/pydanclick/pull/25">Exception catching refactoring</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/179">Stop support for Python 3.9</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;été 2024</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2024" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2024</id>
        <updated>2024-09-21T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://pygments.org/">Pygments</a></h2>
<p><em>Bibliothèque Python de coloration syntaxique</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/2757">Ajout du champ Changed-By au lexeur debian/control</a></li>
<li><a href="https://github.com/pygments/pygments/pull/2767">Correction de l'interprétation de caractère de commentaire dans une chaîne de caractères</a> entourées de guillemets dans le lexeur IniLexer</li>
</ul>
<h2><a href="https://pspdev.github.io/pspsdk/index.html">PSPSDK</a></h2>
<p><em>Ensemble d'outils et de bibliothèques pour la console PSP de Sony</em></p>
<ul>
<li>Amélioration de la documentation : <a href="https://github.com/pspdev/pspsdk/pull/234">correction d'un lien vers la licence</a>, <a href="https://github.com/pspdev/pspsdk/pull/235">suppression d'un fichier README obsolète</a> et <a href="https://github.com/pspdev/pspsdk/pull/236">correction d'erreurs typographiques</a></li>
</ul>
<h2>apt-setup</h2>
<p><em>Partie de Debian-Installer. Produit un fichier /etc/apt/sources.list pour le système installé</em></p>
<ul>
<li>Amélioration de la documentation : <a href="https://salsa.debian.org/installer-team/apt-setup/-/merge_requests/18">rattrapage du comportement actuel de 01setup</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/35">Modèles dynamiques à partir de schémas</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/38">Support de modèles avec plusieurs extensions</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/40">Export de modèles vers des schémas</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/41">Correctif sur la casse des attributs</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/44">Les extensions utilisent des champs Pydantic</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/47">Correctif sur la casse des attributs</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/52">Correctif sur l’ordre des schémas de <code>ListResponse</code></a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/65">Correctifs sur le typage</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/66">Utilisation de paramètres de types pour <code>ListResponse</code></a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/67">Correctifs sur le typage</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/68">Correctifs d’avertissements dans les tests unitaires</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/69">Réusinage du mécanisme d’extensions</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/71">Tests des projets en aval dans l’intégration continue</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/76">Correctif sur l’usage des discriminants Pydantic</a></li>
<li><a href="https://github.com/yaal-coop/scim2-models/pull/78">Les charges utiles des extensions sont facultatives</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-client">scim2-client</a></h2>
<p><em>Fabrication et analyse pythonique de requêtes SCIM</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-client/pull/20">Support des charset dans l’entête <code>Content-Type</code></a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-tester">scim2-tester</a></h2>
<p><em>Outil de vérification de conformité de serveurs aux normes SCIM</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-tester/pull/5">Documentation sur l’usage</a></li>
<li><a href="https://github.com/yaal-coop/scim2-tester/pull/7">Correctif sur la manipulation des erreurs réseau</a></li>
<li><a href="https://github.com/yaal-coop/scim2-tester/pull/9">Compatibilité avec scim2-client 0.2.0</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-cli">scim2-cli</a></h2>
<p><em>Outil en ligne de commandes pour interagir avec des applications SCIM</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-cli/pull/7">Paramètres de commandes dynamiques</a></li>
<li><a href="https://github.com/yaal-coop/scim2-cli/pull/10">Documentation sur la fabrication des binaires</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-server">scim2-server</a></h2>
<p><em>Prototype de server SCIM2 ultra-léger</em></p>
<ul>
<li><a href="https://github.com/yaal-coop/scim2-server/pull/3">Le préfixe <code>/v2</code> est optionnel</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Bibliothèque python de gestion des identités et des accès</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/676">Mise à jour d'actions GHA</a></li>
</ul>
<h2><a href="https://github.com/element-hq/synapse">synapse</a></h2>
<p><em>Serveur Matrix écrit en Python/Twisted</em></p>
<ul>
<li><a href="https://github.com/element-hq/synapse/pull/17667">Réusinage des imports Pydantic</a></li>
</ul>
<h2><a href="https://felix-martel.github.io/pydanclick">pydanclick</a></h2>
<p><em>Ajoutez des options Click à partir de modèles Pydantic</em></p>
<ul>
<li><a href="https://github.com/felix-martel/pydanclick/pull/25">Réusinage sur le traitement d’une exception</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur d’identité et d'autorisations ultra-léger</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/179">Arrêt du support pour Python 3.9</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Notre guide pour sécuriser votre instance GitLab</title>
        <link href="https://bearstech.com/societe/blog/notre-guide-pour-securiser-votre-instance-gitlab" />
        <id>https://bearstech.com/societe/blog/notre-guide-pour-securiser-votre-instance-gitlab</id>
        <updated>2024-09-10T16:08:08Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>bearstech</name>
        </author>
    </entry>
    <entry>
        <title>Les bonnes pratiques du Gitflow avec Gitlab</title>
        <link href="https://bearstech.com/blog/les-bonnes-pratiques-du-gitflow-avec-gitlab" />
        <id>https://bearstech.com/blog/les-bonnes-pratiques-du-gitflow-avec-gitlab</id>
        <updated>2024-09-03T13:31:59Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>emazurier</name>
        </author>
    </entry>
    <entry>
        <title>Spring 2024 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-printemps-2024" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-printemps-2024</id>
        <updated>2024-06-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://github.com/sharkdp/bat">Bat</a></h2>
<p><em>A cat(1) clone with syntax highlighting and Git integration</em></p>
<ul>
<li><a href="https://github.com/sharkdp/bat/pull/2838">Display which theme is the default one</a> with <code>--list-themes</code> parameter and disabled colors. With this PR, bat has the same behaviour than with enabled colors (done in <a href="https://github.com/sharkdp/bat/pull/2838">previous PR</a>).</li>
<li>Improve <a href="https://github.com/sharkdp/bat/pull/2942">code coverage</a> for <code>--list-languages</code> parameter</li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/166">Update to HTMX 1.9.11</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/167">Use the standard python module to parse toml</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/168">Use a better theme for the documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/170">Validate the configuration with pydantic-settings</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/171">Fix a retrocompatibility bug involving LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/172">Update to HTMX 1.9.12</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/173">Group member removal from the group management page</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/174">Model management commands</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/175">Use cases documentation</a></li>
</ul>
<h2><a href="https://github.com/spiral-project/ihatemoney">ihatemoney</a></h2>
<p><em>A simple shared budget manager web application</em></p>
<ul>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1298">Packaging issue fix with python 3.12</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1305">Unit tests speed-up</a></li>
</ul>
<h2><a href="https://github.com/simon-weber/python-libfaketime">python-libfaketime</a></h2>
<p><em>A fast time mocking alternative to freezegun that wraps libfaketime.</em></p>
<ul>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/65">Support for python 3.8 to 3.12</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/67">Use markdown instead of RST in the documentation</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/68">Benchmark script fix</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/69">Documentation improvements</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/71">pytest-libfaketime URL update</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/72"><code>quiet</code> implementation parameter</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/73">GitHub Actions support</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/75">Bump to libfaketime 0.9.10</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/77">README GHA badge fix</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/78">Timestamp file support</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/79">README documentation fix</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/80">Linters configuration</a></li>
</ul>
<h2><a href="https://github.com/pytest-dev/pytest-libfaketime">pytest-libfaketime</a></h2>
<p><em>Prepare pytest for python-libfaketime</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-libfaketime">Move to GitHub under the pytest-dev umbrella</a></li>
<li><a href="https://pypi.org/project/pytest-libfaketime/0.1.3/">0.1.3 release</a></li>
</ul>
<h2><a href="https://github.com/pytest-dev/pytest-iam">pytest-iam</a></h2>
<p><em>A fully functional OAUTH2 / OpenID Connect (OIDC) server to be used in your testsuite</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-iam">Move to GitHub under the pytest-dev umbrella</a></li>
<li><a href="https://pypi.org/project/pytest-iam/0.0.10/">0.0.10 release</a></li>
</ul>
<h2>Debian</h2>
<ul>
<li>Extract <a href="https://salsa.debian.org/games-team/blastem/-/merge_requests/3">BlastEm</a> manpage because it does not existe anymore in the upstream repository</li>
<li>Update improved <a href="https://salsa.debian.org/games-team/blastem/-/merge_requests/2">BlastEm</a> manpage to the new manpage</li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-models">scim2-models</a></h2>
<p><em>SCIM resources serialization and validation with Pydantic</em></p>
<ul>
<li><a href="https://scim2-models.readthedocs.io">Initial releases and documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-client">scim2-client</a></h2>
<p><em>Pythonically build SCIM requests and parse SCIM responses</em></p>
<ul>
<li><a href="https://scim2-client.readthedocs.io">Initial releases and documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-tester">scim2-tester</a></h2>
<p><em>SCIM RFCs server compliance checker</em></p>
<ul>
<li><a href="https://scim2-tester.readthedocs.io">Initial releases and documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-cli">scim2-cli</a></h2>
<p><em>SCIM application development CLI</em></p>
<ul>
<li><a href="https://scim2-cli.readthedocs.io">Initial releases and documentation</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant le printemps 2024</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-printemps-2024" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-printemps-2024</id>
        <updated>2024-06-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://github.com/sharkdp/bat">Bat</a></h2>
<p><em>Un clone de cat(1) avec coloration syntaxique et intégration Git</em></p>
<ul>
<li><a href="https://github.com/sharkdp/bat/pull/2937">Affiche quel est le thème par défaut</a> lors de l'utilisation du paramètre <code>--list-themes</code> et la coloration désactivée. Cette PR permet d'avoir un comportement cohérent avec la <a href="https://github.com/sharkdp/bat/pull/2838">PR précédente</a> où la coloration est activée.</li>
<li>Amélioration de la <a href="https://github.com/sharkdp/bat/pull/2942">couverture de code</a> lors de l'utilisation du paramètre <code>--list-languages</code></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/166">Mise à jour vers HTMX 1.9.11</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/167">Utilisation du module standard python pour charger les fichiers toml</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/168">Utilisation d’un meilleur thème pour la documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/170">Validation de la configuration avec pydantic-settings</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/171">Correction d’un souci de rétrocompatibilité impliquant LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/172">Mise à jour vers HTMX 1.9.12</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/173">Suppression des membres d’un groupe depuis la page d’édition du groupe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/174">Commandes de gestion des modèles</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/175">Documentation des cas d’usage</a></li>
</ul>
<h2><a href="https://github.com/spiral-project/ihatemoney">ihatemoney</a></h2>
<p><em>Une application web simple de gestion de budget</em></p>
<ul>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1298">Correctif de création de paquets avec python 3.12</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1305">Accélération des tests unitaires</a></li>
</ul>
<h2><a href="https://github.com/simon-weber/python-libfaketime">python-libfaketime</a></h2>
<p><em>Une alternative rapide à freezegun pour mocker les dates, en utilisant libfaketime</em></p>
<ul>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/65">Support des versions de python 3.8 à 3.12</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/67">Utilisation de markdown à la place de RST dans la documentatino</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/68">Correctif du script de benchmark</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/69">Améliorations sur la documentation</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/71">Mise à jour de l’URL de pytest-libfaketime</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/72">Implémentation du paramètre <code>quiet</code></a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/73">Support de GitHub Actions</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/75">Mise à jour vers libfaketime 0.9.10</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/77">Correction du lien du badge GHA sur le fichier README</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/78">Support des fichiers <code>timestamp</code></a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/79">Correction sur la documentation du README</a></li>
<li><a href="https://github.com/simon-weber/python-libfaketime/pull/80">Configuration des outils d’analyse statique</a></li>
</ul>
<h2><a href="https://github.com/pytest-dev/pytest-libfaketime">pytest-libfaketime</a></h2>
<p><em>Prepare pytest à l’utilisation de python-libfaketime</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-libfaketime">Déménagement dans le group pytest-dev de GitHub</a></li>
<li><a href="https://pypi.org/project/pytest-libfaketime/0.1.3/">0.1.3 release</a></li>
</ul>
<h2><a href="https://github.com/pytest-dev/pytest-iam">pytest-iam</a></h2>
<p><em>Serveur OAuth2/OIDC léger pour suites de tests unitaires</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest-iam">Déménagement dans le group pytest-dev de GitHub</a></li>
<li><a href="https://pypi.org/project/pytest-iam/0.0.10/">0.0.10 release</a></li>
</ul>
<h2>Debian</h2>
<ul>
<li>Extraction de la page de manuel de <a href="https://salsa.debian.org/games-team/blastem/-/merge_requests/3">BlastEm</a> car elle n'est plus dans le dépôt amont</li>
<li>Mise-à-jour de l'amélioration de la page de manuel de <a href="https://salsa.debian.org/games-team/blastem/-/merge_requests/2">BlastEm</a> sur la page de manuel nouvellement extraite</li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-models">scim2-models</a></h2>
<p><em>Sérialisation et validation de ressources SCIM avec Pydantic</em></p>
<ul>
<li><a href="https://scim2-models.readthedocs.io">Publication initiale et documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-client">scim2-client</a></h2>
<p><em>Fabrication et analyse pythonique de requêtes SCIM</em></p>
<ul>
<li><a href="https://scim2-client.readthedocs.io">Publication initiale et documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-tester">scim2-tester</a></h2>
<p><em>Outil de vérification de conformité de serveurs aux normes SCIM</em></p>
<ul>
<li><a href="https://scim2-tester.readthedocs.io">Publication initiale et documentation</a></li>
</ul>
<h2><a href="https://github.com/yaal-coop/scim2-cli">scim2-cli</a></h2>
<p><em>SCIM application development CLI</em></p>
<ul>
<li><a href="https://scim2-cli.readthedocs.io">Publication initiale et documentation</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Comment parler de politique</title>
        <link href="https://dmerej.info/blog/fr/post/comment-parler-de-politique/" />
        <id>https://dmerej.info/blog/fr/post/comment-parler-de-politique/</id>
        <updated>2024-06-13T11:04:10Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1 id="introduction">Introduction <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#introduction">#</a></h1>
<p>L’heure est grave.</p>
<p>Dans 3 semaines, il y a une possibilité que l’extrême droite obtienne une majorité absolue à l’Assemblée Nationale.</p>
<p>Qu’est-ce que ça aura pour conséquences?</p>
<ol>
<li>
<p>Emmanuel Macron devra nommer un premier Ministre <em>qui ne soit pas
rejeté par une majorité à l’Assemblée</em> - pas le choix, ça sera Jordan Bardella.</p>
</li>
<li>
<p>On rentera dans une cohabitation, avec un Président qui a très peu de
pouvoir, et un Premier Ministre qui gouverne, donc <strong>une politique d’extrême-droite pendant 3 ans</strong>
(ni le Président ni le Sénat pourront empêcher le RN de voter les lois de son programme - seul le
Conseil Constitutionnel pourra empêcher les votes des lois les plus dures).</p>
</li>
<li>
<p>En 2027, Marine Le Pen remportera l’élection présidentielle et la France basculera vers le fascisme.</p>
</li>
</ol>
<p>Les deux premiers points sont assez certains, cela découle naturellement du
fonctionnement de nos institutions. Le troisième point est assez probable si
l’on se base sur les précédents historiques - en tout cas, il donne une
idée de l’importance colossale de ces législatives anticipées.</p>
<h1 id="mes-convictions">Mes convictions <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#mes-convictions">#</a></h1>
<p>Je suis convaincu de plusieurs choses:</p>
<ol>
<li>Le scénario décrit en introduction est crédible et peut nous amener au fascisme en
France en 2027</li>
<li>La meilleure stratégie pour éviter cela c’est de faire barrage au RN lors des
législatives</li>
<li>Le meilleur moyen de faire barrage au RN c’est de <strong>voter massivement
pour les candidats et candidates Front Populaire dès le premier tour</strong>.</li>
<li>Le pire peut arriver, mais la bonne nouvelle c’est qu’il est aussi
possible d’avoir une majorité Front Populaire à l’Assemblée
Nationale - et ça, ça serait une vraie rupture avec les 7 dernières années de Macronisme.</li>
<li>Vous qui me lisez, vous pouvez y faire quelque chose, et ce dès le premier tour.</li>
<li>Le résultat du vote du 29 juin dépendra en grande partie des
conversations que vous aurez autour de vous.</li>
</ol>
<p>Le dernier point est important et je trouve qu’on en parle pas assez -
et donc il mérite sa propre section.</p>
<h1 id="de-limportance-des-conversations">De l’importance des conversations <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#de-limportance-des-conversations">#</a></h1>
<p>La question à se poser c’est : pourquoi est-ce que le Front Populaire ferait mieux en 2024 que la NUPES
en 2022?</p>
<p>Notamment, qu’est-ce qui va pousser des personnes qui <em>n’ont pas voté du
tout</em> ou ont voté autre chose que NUPES à voter Front Populaire?</p>
<p>Je pense que cela passera par une foule de gens (dont vous qui me lisez, j’espère)
qui auront des <em>conversations</em> et <em>arriveront à convaincre</em> des indécis.</p>
<p>Pourquoi je pense que cela va marcher?</p>
<p>Je ne sais pas. Je n’ai pas de bon argument. C’est quelque chose que
j’ai choisi de croire. Comme disait Chomsky:</p>
<blockquote>
<p>If you assume that there is no hope, you guarantee that there will be no
hope. If you assume that there is an instinct for freedom, that there
are opportunities to change things, then there is a possibility that you
can contribute to making a better world.</p>
</blockquote>
<p>Traduction :</p>
<blockquote>
<p>Si vous partez du principe qu’il n’y a pas d’espoir, alors il ne pourra pas y en avoir.
Si vous partez du principe qu’il existe un instinct pour la liberté, qu’il y a des opportunités
pour changer les choses, alors il est possible que vous puissiez contribuer à bâtir un monde meilleur.</p>
</blockquote>
<p>Si vous avez tenu jusque là, on peut rentrer dans le vif du sujet.</p>
<h1 id="parler-politique-mode-demploi">Parler politique, mode d’emploi <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#parler-politique-mode-demploi">#</a></h1>
<p>Quand je parle de conversation, je parle de <em>deux personnes qui
discutent ensemble</em> - surtout pas d’un débat devant un public!</p>
<p>Assurez-vous que la personne avec qui vous discutez souhaite parler de
politique (ça reste un tabou pour beaucoup de gens).</p>
<p>Si la personne vous dit “je compte m’abstenir”, “je compte voter
blanc”, “je compte voter RN”, <strong>ne la jugez pas</strong>. Au contraire,
écoutez-la et montrez-vous curieux. Exemple:</p>
<p>— Je ne peux pas voter pour le Front Populaire parce que Mélenchon et la LFI me font peur.</p>
<p>— Je comprends. Beaucoup de gens ont peur de la LFI.  Qu’est-ce qui te fait peur chez LFI?</p>
<p>— Ce sont des extrémistes.</p>
<p>— Comment ça?</p>
<p>— Ils soutiennent les islamistes.</p>
<p>— Qu’est-ce que tu entends par islamistes?</p>
<p>— Ben, les terroristes du Hamas, tout ça. En plus ils sont antisémites.</p>
<p>Vous voyez l’idée - commencez par écouter et comprendre les émotions de
la personne avec qui vous discutez <em>avant</em> de présenter votre point de
vue.</p>
<p>Ici par exemple, vous pouvez esquiver le sujet de l’antisémitisme
(reconnaissons-le, c’est un sujet important mais compliqué) et plutôt
expliquer la différence entre soutenir Gaza et soutenir le terrorisme.</p>
<p>Mettez de l’eau dans votre vin! Vous n’avez pas besoin de défendre votre
parti (ou votre personne) préférée sur tous les points. De toutes façon
le Front Populaire c’est une coalition de gauche qui va de la LFI au PS
en passant par les écologistes et le parti communiste. Si vous êtes fan
d’Untel ou Unetelle mais que la personne que vous voulez convaincre la
déteste dites simplement “je sais - beaucoup de gens pensent comme toi -
c’est une personnalité clivante” et passez à la suite.</p>
<p>L’important c’est de prendre en compte les sentiments, les émotions et
les besoins de la personne avec qui vous discutez - sinon vous allez la
braquer et vous n’arriverez pas à la convaincre.</p>
<p>Autre exemple:</p>
<p>— Je vais pas voter parce que mon vote sert à rien</p>
<p>—  Pourquoi tu penses que ton vote ne sert à rien?</p>
<p>— Parce qu’une fois élus ils font le contraire de ce qu’ils ont promis</p>
<p>— Je sais. En fait c’est plutôt logique vu le fonctionnement des
institutions. Mais ce n’est pas l’enjeu. L’enjeu c’est d’empêcher
l’extrême-droite d’arriver au pouvoir.</p>
<p>Et là vous pouvez rentrer sur <em>pourquoi</em> la perspective de l’extrême droite
au pouvoir vous touche <em>vous</em>, personnellement, ou bien vos proches.</p>
<p>Ainsi, vous allez vous montrer vulnérable et ce sera plus facile d’instaurer
une confiance réciproque.</p>
<p>Finalement, contentez-vous de petites victoires.  Il est très difficile de faire
changer d’avis quelqu’un. Cela dit, si vous vous y prenez correctement vous
aurez planté des graines qui écloront plus tard.</p>
<p>Souvenez-vous aussi qu’il est plus facile pour quelqu’un de changer
d’avis quand plusieurs personnes différentes lui parlent du même
sujet.</p>
<h1 id="conclusion">Conclusion <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusion">#</a></h1>
<p>C’est le premier article qui parle explicitement de politique sur ce blog
depuis sa création 2016, mais je ne pouvais pas ne pas l’écrire.</p>
<p>J’ai quelques idées sur la suite à donner, mais cela dépendra beaucoup
de vos retours, chers lecteurs et lectrices.</p>
<p>Vous noterez que les commentaires sous ce billet sont désactivés parce
que, justement, si le sujet vous intéresse, je veux avoir une vraie
conversation avec vous ;)</p>
<p>Enfin et si vous le souhaitez, n’hésitez pas à partager cet article
autour de vous, ça m’intéresse de recueillir une variété de points de
vue.</p>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>PyConFR 2024 — Strasbourg</title>
        <link href="https://zestedesavoir.com/billets/4677/pyconfr-2024-strasbourg/" />
        <id>https://zestedesavoir.com/billets/4677/pyconfr-2024-strasbourg/</id>
        <updated>2024-05-22T12:02:07Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                L'appel à participations est ouvert !
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Chapitre 2023</title>
        <link href="https://yaal.coop/blog/chapitre-2023" />
        <id>https://yaal.coop/blog/chapitre-2023</id>
        <updated>2024-05-14T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Une année de plus au compteur pour Yaal Coop !</p>
<p>Nous vous avons assez peu régalé en articles de blog cette année, mais l'une de nos dernières publications ne vous a probablement pas échappé : <a href="https://yaal.coop/blog/yaal-coop-recrute">Yaal Coop recrute !</a></p>
<p>Ce que ça veut dire, entre autres choses, c'est qu'il y a de l'activité dans la SCIC ! Notre Assemblée Générale Ordinaire s'est déroulée le 29 avril 2024, en faisant le tour de l'année 2023, de ses projets, de nos objectifs coopératifs et de nos perspectives pour l'année en cours.</p>
<p>Sans plus attendre, notre rapport de gestion :</p>
<hr/>
<p>Cher·e sociétaire,</p>
<p>Nous avons l’honneur de vous présenter notre rapport sur les opérations de l’exercice clos le 31 décembre 2023, ainsi que sur les comptes annuels dudit exercice soumis aujourd’hui à votre approbation. Ce rapport a été rédigé collectivement par le collège des salarié·es de Yaal Coop.</p>
<hr/>
<h2>Les faits marquants et nos projets en 2023</h2>
<h3>Déménagement</h3>
<p>En Septembre 2023, Yaal Coop a déménagé et s'est installé à Bègles, au 16 Rue des Terres Neuves !</p>
<p>Après de longs mois de travaux, la coopérative s'installe dans ses nouveaux locaux et y accueille un mois plus tard ses premiers locataires.</p>
<p>Actuellement et depuis l'ouverture du local, Yaal Coop en assure la gestion administrative et quotidienne, et recherche toujours de nouveaux locataires.</p>
<p>Sur l'année 2023, la gestion de la SCI par Yaal Coop a occupé environ 13% de notre temps, et la coopérative mise sur une réduction de ce temps à mesure que la routine de gestion s'installe, que les travaux d'aménagement se terminent et que l'occupation des locataires se stabilise.</p>
<h3>Nos Projets</h3>
<h4>Portail RSE</h4>
<p><a href="https://portail-rse.beta.gouv.fr/">https://portail-rse.beta.gouv.fr/</a></p>
<p>Camille et Stéphane poursuivent le développement de la plateforme Portail RSE (anciennement Projet IMPACT), Start-up d'État faisant partie du programme beta.gouv et pilotée par la Direction Générale des Entreprises.</p>
<p>Brunélie rejoint le projet en tant qu'UX/UI designer et à l'intégration à la fin de l'été.</p>
<p>Des nouvelles réglementations sont ajoutées à la plateforme, et les textes réglementaires de la CSRD, cible importante pour le produit, arrivent en fin d'année. Les premières étapes sur le chantier CSRD sont publiés sur le Portail RSE en décembre 2023.</p>
<h3>Lum1</h3>
<p>Lum1 était un projet d'investissement technique qui proposait un annuaire collaboratif dédié et réservé aux professionnels du social et de la santé.</p>
<p>Après des avancées techniques, les développements se sont ralentis puis, en l'absence de perspectives commerciales, la décision de fermer l'entreprise Lum1 a été prise par l'ensemble de ses actionnaires en novembre 2023. La valorisation des actions détenues par Yaal Coop dans Lum1 devient donc nulle.</p>
<h3>PodEduc</h3>
<p><a href="https://podeduc.apps.education.fr/">https://podeduc.apps.education.fr/</a></p>
<p>PodEduc est un projet d’hébergement et de montage de vidéos à destination de l’éducation nationale. Loan et Éloi ont réalisé une mission qui permet une meilleure intégration du projet sur mobile.</p>
<h3>B3Desk</h3>
<p><a href="https://github.com/numerique-gouv/b3desk">https://github.com/numerique-gouv/b3desk</a></p>
<p>B3Desk est un projet de gestion des accès aux plateformes de visioconférences utilisées par l’éducation nationale.</p>
<p>Loan et Éloi ont travaillé sur B3Desk au long cours pour développer les fonctionnalités, corriger les dysfonctionnement, documenter et renseigner les équipes techniques.</p>
<h3>Telecoop</h3>
<p>Un backoffice pour la gestion des lignes téléphoniques et des factures à été livré en début d'année. Il a été réalisé dans le but de dégager du temps à l'équipe technique en donnant de l'autonomie aux responsables clients.</p>
<p>Des évolutions de ce service ont ensuite débuté à la fin de l'année (et se poursuivent aujourd'hui) pour offrir plus de possibilités d'actions et de présentation.</p>
<h3>G4 Ingénierie</h3>
<p>G4Ingénierie est un bureau d'ingénierie en géomatique.
Nous avons réalisé pour ce client un petit projet leur permettant de mettre en ligne les représentations cartographiques qu’ils produisent.</p>
<h3>Canaille</h3>
<p><a href="https://canaille.yaal.coop/">https://canaille.yaal.coop/</a></p>
<p>Canaille est notre logiciel libre de gestion d'identité et d'autorisations développé en interne.</p>
<p>De nouveaux développements ont été réalisés en 2023, en partie grâce au financement de 7k€ accordé par la fondation européenne NLnet. Un <a href="https://yaal.coop/blog/canaille-nlnet-pytest-iam">article de blog</a>  a été publié pour retracer l'histoire du logiciel et préciser les développements réalisés avec l'aide de NLnet.</p>
<h3>Nubla</h3>
<p><a href="https://nubla.fr/">https://nubla.fr/</a></p>
<p>Nubla est notre service d'e-mail, cloud et messagerie à destination des particuliers et professionnels.</p>
<p>Nous n'avons malheureusement eu que trop peu de temps dédié au développement technique et commercial de ce projet interne en 2023. Mais le service actuel est toujours fonctionnel et tous nos clients ont renouvelé leur confiance et leur abonnement !</p>
<h3>GeoNature - citizen</h3>
<p><a href="https://enquetes.lashf.org/fr/home">https://enquetes.lashf.org/fr/home</a></p>
<p>La SHF, Société Herpétologique de France, nous a approché pour faire évoluer une solution libre d'inventaires participatifs pour pouvoir passer d'une ancienne solution, à cet outil : GeoNature - citizen.</p>
<p>Le besoin était d'implémenter une étape de validation des observations réalisées par les participants jusque là absente de la solution. Cette solution est intégrée à un projet plus vaste d'éducation et de recensement des amphibiens et reptiles : <a href="https://undragon.org/">https://undragon.org/</a></p>
<h3>Yuticket</h3>
<p><a href="https://www.yuticket.com/">https://www.yuticket.com/</a></p>
<p>Yuticket est une billeterie en ligne dont Yaal Coop fait la maintenance. Le service évolue peu.</p>
<h3>Supercoop</h3>
<p>En 2023, Camille et Eloi ont continué de consacrer 1 journée par mois au supermarché coopératif de Bordeaux en bénévolat pour les aider sur la maintenance et le développement de leurs outils informatiques.</p>
<hr/>
<h2>Notre projet coopératif</h2>
<h3>Sociétariat</h3>
<p>Excepté Julien, salarié du 27 décembre 2022 au 30 juin 2023, tous⋅tes les salarié⋅es étaient également associé⋅es de Yaal Coop au cours de l'année 2023 et détiennent chacun⋅e une voix égale au sein du collège des salarié⋅es, conformément à nos statuts.</p>
<p>En avril 2023, Colin Garriga-Salaün est devenu associé et a rejoint en son nom propre le collège des observateurs. Son entrée a été confirmée lors de la précédente AG annuelle du 09 mai 2023.</p>
<p>Il n'y a eu aucune modification du sociétariat depuis et la composition des collèges n'a donc pas évoluée depuis le dernier rapport de gestion 2022. Elle est toujours la suivante en date du 29 avril 2024 :</p>
<p>Collège des salariés - 50% des droits de vote</p>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE</th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>Brunélie LAURET</td>
<td>100</td>
</tr>
<tr>
<td>Camille DANIEL</td>
<td>100</td>
</tr>
<tr>
<td>Loan ROBERT</td>
<td>100</td>
</tr>
<tr>
<td>Stéphane BLONDON</td>
<td>100</td>
</tr>
<tr>
<td>Éloi RIVARD</td>
<td>100</td>
</tr>
</tbody>
</table>
<p>Collège des investisseurs - 16,66% des droits de vote</p>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE</th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>GRUYERE</td>
<td>50 000</td>
</tr>
</tbody>
</table>
<p>Collège des bénéficiaires - 16,66% des droits de vote</p>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE</th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>FINACOOP NOUVELLE-AQUITAINE</td>
<td>100</td>
</tr>
</tbody>
</table>
<p>Collège des observateurs - 16,66% des droits de vote</p>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE</th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>Arthur LEDARD</td>
<td>100</td>
</tr>
<tr>
<td>Colin GARRIGA-SALAÜN</td>
<td>100</td>
</tr>
</tbody>
</table>
<h3>Favoriser une organisation horizontale</h3>
<h4>Présidence de Brunélie (actée à l'AG précédente)</h4>
<p>Suite à la décision prise à l'Assemblée Générale Ordinaire de clôture de l'exercice 2022, Brunélie LAURET assure dorénavant la présidence officielle de Yaal Coop depuis le 9 mai 2023.</p>
<h4>Évolutions dans notre gouvernance</h4>
<p>Notre organisation et en particulier notre gouvernance, dirigée par les coopérateur⋅ices salarié·es et inspirée de l'holacratie, évolue au fil du temps. Celle-ci est revue et éventuellement modifiée lors de nos réunion de gouvernance qui ont lieu trimestriellement.</p>
<p>En 2023, les rôles de communication et de commerce ont été rassemblés en un seul, assumé par l'ensemble des salarié·es. Les rôles individuels pré-existants, dont les redevabilités étaient d'avoir et de veiller au respect d'une stratégie de communication pour l'un, et d'une stratégie commerciale pour l'autre, ont été supprimés sur le constat que ces rôles n'étaient pas réellement incarnés. Les redevabilités ont été affinées et comprennent notamment accueillir et répondre aux prospects, surveiller les opportunités et offres d'emploi/missions sur différentes sources, etc.</p>
<p>Un rôle a été créé pour assurer la représentation de la coopérative au sein du collectif CHATONS (Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires) auquel nous appartenons, tout comme un autre existait déjà pour représenter Yaal Coop au sein du réseau Libre-Entreprise.</p>
<p>Le rôle "Grand⋅e coopérateur⋅ice" s'assurant du bon déroulement des Assemblées Générales, de l'actualisation du registre des sociétaires, de l'intégration des associé⋅es a été mis à jour pour le fusionner avec le rôle de Président⋅e, avec la responsabilité de s'assurer que les formalités administratives soient traitées. Sa durée a été allongée à 2 ans.</p>
<p>Les rôles tournants définis actuellement sont les suivants :</p>
<ul>
<li>💌 Facteur·rice (qui relève le courrier entrant de nos différents boîtes mail et postale communes) - 2 semaines</li>
<li>📟 Sentinelle (qui surveille les alertes levées par notre système de monitoring technique) - 2 semaines</li>
<li>✒️ Secrétaire (qui programme et prend des notes de nos réunions régulières) - 3 mois</li>
<li>🗨️ Facilitateur·rice (qui anime nos réunions régulières) - 3 mois</li>
<li>🏦 Billetterie (qui fait la paie) - 3 mois</li>
<li>🍲 Ticket-Restaurateur·rice (qui gère la distribution des tickets restaurants) - 3 mois</li>
<li>📜 Marteau de la Justice (qui s'assure Yaal Coop respecte ses obligations légales) - 6 mois</li>
<li>🕊️ Libre Entrepriseur·euse (qui représente Yaal Coop au sein du réseau Libre-entreprise) - 6 mois</li>
<li>😽 Chaton·ne (qui représente Yaal Coop au sein du collectif CHATONS) - 1 an</li>
<li>🪙 Argentier·e (qui suit et budgétise la trésorerie) - 1 an suivi de 1 an en backup</li>
<li>🎊 Grand·e Coopérateur·rice (qui porte le mandat de Président·e, organise les Assemblées Générales et le sociétariat et s'assure que les formalités administratives sont traitées) - 2 ans</li>
</ul>
<p>Ils sont complétés par 4 rôles permanents occupés par tous les salariés :</p>
<ul>
<li>🚀 Responsable projet/prospect (qui est le référent d'un projet et le contact privilégié de ses éventuels clients)</li>
<li>🛠️ Producteur·rice (qui produit du travail de qualité et se forme sur son métier)</li>
<li>🎯 Chasseur·euse cueilleur·euse (qui s'occupe de la communication et du commerce)</li>
<li>👤 Salarié·e (qui remplit ses obligations de salariés)</li>
</ul>
<p>Tous ces rôles ont une liste de redevabilités associées qui évolue également en fonction des besoins et des constats/manques éventuels observés.</p>
<p>Nos réunions hebdomadaires de suivi de l'activité et les réunions trimestrielles de stratégie sur l'investissement réunissant les salarié·es sont toujours en place.</p>
<h3>Favoriser l'activité et les acteurs ayant un impact social ou environnemental, de préférence locaux</h3>
<h4>Répartition du temps d'occupation</h4>
<p>En 2023, le temps d'occupation de Yaal Coop a été réparti comme suit :</p>
<table>
<thead>
<tr>
<th>Activité</th>
<th>Temps (pourcentage)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prestation client</td>
<td>42%</td>
</tr>
<tr>
<td>Gestion de Yaal Coop</td>
<td>33%</td>
</tr>
<tr>
<td>Gestion de la SCI</td>
<td>13%</td>
</tr>
<tr>
<td>Investissement technique (Lum1)</td>
<td>6,6%</td>
</tr>
<tr>
<td>Investissement interne (Nubla, Canaille)</td>
<td>3%</td>
</tr>
<tr>
<td>Bénévolat</td>
<td>1,6%</td>
</tr>
<tr>
<td>Investissement subventionné (NLNet)</td>
<td>0,6%</td>
</tr>
</tbody>
</table>
<p><img alt="Répartition du temps au cours de l'année 2023" src="https://yaal.coop/media/blog/articles/Temps2023.png"/></p>
<p>Au cours de nos réunions d'équipe trimestrielles de stratégie sur l'investissement, nous nous fixons des objectifs de répartition de notre temps de travail. Nos objectifs actuels sont les suivants :</p>
<table>
<thead>
<tr>
<th>Gestion de la SCI</th>
<th>Gestion de Yaal Coop</th>
<th>Investissement</th>
<th>Prestation</th>
</tr>
</thead>
<tbody>
<tr>
<td>15% ponctuellement (puis 10%)</td>
<td>25%</td>
<td>10%</td>
<td>50%</td>
</tr>
</tbody>
</table>
<p>La répartition du travail actuelle, et sur l'ensemble de l'année 2023, a pesé en faveur des prestations et moins des projets d'investissement internes (Nubla et Canaille notamment) ou technique (qui s'est ralenti puis arrêté pour le moment avec la fin du projet Lum1).</p>
<h4>Économie Sociale et Solidaire (ESS)</h4>
<p>Nos projets et fournisseurs ayant peu changé en 2023, le constat est le même qu'en 2022 : nous continuons de favoriser les acteurs de l'économie sociale et solidaire en plus des missions de service public, et en particulier les coopératives.</p>
<p>Nous n'avons pas souscrit de nouvelles parts de capital social mais nous possédons toujours celles de notre banque Crédit Coopératif (10 parts pour un montant de 152,50€), notre cabinet comptable Finacoop (1 part de 100€), notre cabinet de paie Assistea (1 part de 100€), et notre fournisseur téléphonique mobile et client Telecoop (1 part de 100€).</p>
<h4>Impact environnemental</h4>
<p>Les nouveaux locaux que Yaal Coop occupent ont été entièrement rénovés avant notre emménagement, avec une attention forte à l'impact environnemental : étude environnementale préalable aux travaux, optimisation de l’existant et réemploi (de l'isolant notamment), mise en place d'une pompe à chaleur pour le chauffage, installation d'ouvertures contrôlables et de ventilateurs au plafond pour éviter la climatisation...</p>
<p>Conformément à nos convictions, et comme les années précédentes, Yaal Coop a versé à l'ensemble de l'équipe salariée le forfait mobilité durable à hauteur de 700€ par an, pour maintenir et encourager l'utilisation de mobilités douces (le vélo principalement) dans les déplacements du domicile au lieu de travail.</p>
<p>Pour limiter son empreinte écologique, Yaal Coop a de nouveau privilégié l'achat d'un téléphone portable reconditionné plutôt que neuf et l'amélioration du matériel existant plutôt que son remplacement (via l'achat de RAM par exemple ou le remplacement d'un module de refroidissement).</p>
<p>Enfin la question du numérique soutenable est toujours une question d'intérêt pour la coopérative. Nous continuons de choisir soigneusement les projets sur lesquels nous travaillons pour éviter de contribuer à l'impact du numérique sur des projets que nous jugeons peu utiles voire contre-productifs.</p>
<p>De façon plus anecdotique, sur les logiciels que nous développons (tels que canaille), nous utilisons les outils d’audit à notre disposition pour travailler sur la légèreté des pages générées. Nous essayons notamment de suivre quelques référentiels de bonnes pratiques de conception et de développement :</p>
<ul>
<li><a href="https://gr491.isit-europe.org/">Le GR491</a></li>
<li><a href="https://ecoresponsable.numerique.gouv.fr/publications/referentiel-general-ecoconception/">Le Référentiel général d’écoconception de services numériques (RGESN)</a></li>
<li><a href="https://github.com/cnumr/best-practices/">Les fiches de bonnes pratiques GreenIT</a></li>
</ul>
<p>Afin de réduire les transferts réseau, nous prenons soin de réduire les tailles de nos images, de n’afficher que le contenu nécessaire sur des pages volontairement simples, de réduire la taille du code source que nous transférons. Nous visons des scores d’au moins 90 % ou B sur les outils que nous utilisons pour mesurer la performance de nos pages (tels que lighthouse ou ecoindex.fr).</p>
<h4>Réseaux</h4>
<p>Cette année, Yaal Coop maintient sa participation au sein du Collectif CHATONS, avec la solution d'hébergement, de messagerie et d'e-mail Nubla. La coopérative participe à quelques réunions mensuelles du collectif au cours de l'année, s'exprime et vote lors des prises de décision qui animent le collectif, comme la révision de la charte ayant eu lieu en 2023.</p>
<p>Yaal Coop maintient également sa participation dans le réseau Libre Entreprise, avec le partage de comptes-rendu mensuels résumant les projets de la coopérative, sa vie et son activité, avec la participation aux réunions mensuelles du réseau et avec l'engagement de certain⋅es coopérateur⋅ices sur des chantiers en cours dans le réseau.</p>
<p>Yaal Coop est toujours adhérente du pôle de compétences régional en logiciels et technologies libres et open source NAOS.</p>
<h3>Favoriser l'utilisation et le développement de logiciels libres</h3>
<h4>Projets et missions</h4>
<p>Même s'il ne s'agit pas d'une condition exclusive, la majeure partie de nos projets en 2023 a été réalisée sur du code libre, qu'il s'agisse de nos projets internes (Canaille, Nubla) ou de nos prestations (Portail RSE, PodEduc, B3Desk).</p>
<h4>Contributions de l'année à des logiciels libres</h4>
<p>Les contributions sont résumées chaque saison dans des articles de blog visibles sur notre site web https://yaal.coop/blog/. Elles sont, soit limitées à quelques modifications ciblées sur des logiciels utilisés, soit des contributions au long cours sur quelques bibliothèques et outils spécifiques (en particulier autour de l'écosystème de Canaille).</p>
<h4>Participations</h4>
<p>En plus de nos contributions en développement et/ou design, nous avons décidé de contribuer financièrement à 2 projets libres sur Github que nous utilisons, à hauteur de 20$/mois.</p>
<hr/>
<h2>Vie économique de la coopérative</h2>
<h3>Augmentation salariale</h3>
<p>Fin 2023, compte tenu du bilan positif de la coopérative, l'ensemble des associé⋅es salarié⋅es ont décidé d'une augmentation des salaires, qui avait été repoussée l'année dernière par prudence. Une prime de partage de la valeur a également été versée pour compenser les salaires plus faibles de 2023.</p>
<h3>Bilan financier et compte de résultat 2023</h3>
<p>L'Excédent Brut d'Exploitation est positif et en hausse par rapport à l'exercice précédent. Il en va de même pour le Résultat d'exploitation (hors charges et produits financiers) : 60.538€.  Le résultat comptable est cependant négatif (-87.988€) à cause de la dépréciation d'actif lié à la fermeture de Lum1.</p>
<p>Le Produit Constaté d'Avance (règlements perçus d'avance et comptabilisés en 2023) est de 35.470€ et devrait être exécuté au premier semestre 2024.</p>
<p>Le détail du bilan est disponible dans les comptes annuels 2023 rédigés par notre cabinet d'expertise comptable Finacoop.</p>
<p>Conformément à la dernière décision d'Assemblé Générale, l'intégralité des pertes 2023 est déduite des réserves impartageables de la coopérative.</p>
<p>Aucun dividende n'a été versé depuis le premier exercice comptable de Yaal Coop et la dirigeante ne touche aucune rémunération liée à son statut de dirigeante.</p>
<hr/>
<h2>Perspectives</h2>
<h3>Évolution des projets</h3>
<p>Les principaux projets de l'équipe se poursuivent en 2024 :</p>
<ul>
<li>Portail RSE : la prestation se poursuit au même rythme qu'en 2023 pour le développement mais Brunélie arrête la mission d'UX au printemps.</li>
<li>PodEduc : Une nouvelle mission en 2024 est en cours de réalisation afin de fédérer différentes instances du projet entre elles, ainsi qu'avec des instances de peertube.</li>
<li>B3Desk : l'activité se poursuit sur la première partie de 2024. Le client est satisfait et cherche des financements pour continuer à travailler avec nous pour la seconde partie de 2024.</li>
<li>Telecoop : l'activité s'est poursuivie début 2024 et la pérennisation de notre intervention régulière avec un contrat cadre est en cours de discussion.</li>
<li>Canaille : une nouvelle demande de financement de 30k€ auprès de NLnet a été acceptée le 19 février 2024 pour du développement à venir !</li>
</ul>
<p>Les projections sur les mois à venir continuent ainsi dans le sens de 2023, avec une part importante de notre temps consacré à la prestation et remettant à plus tard dans 2024 l'investissement. Notre souhait à plus long terme reste pour autant de réussir à réunir les conditions pour réaliser plus d'investissement.</p>
<h3>Changements dans l’équipe</h3>
<p>Éloi nous quittera au mois de juin 2024 pour poursuivre des projets personnels. Mais on a espoir de se retrouver plus tard ! Il n'est d'ailleurs pas prévu qu'il quitte le sociétariat, mais qu'il bascule de collège.</p>
<p>Comme un changement ne vient jamais seul, nous projetons en contrepartie de compléter l'équipe salariée de Yaal Coop au travers le recrutement d'un⋅e développeur⋅euse. Le nombre de projets de développement en cours, la nécessité de maintenir au moins la même taille d'équipe, et même de l'agrandir sur le long terme ainsi que la volonté de pouvoir accepter de nouveaux projets motivent ce choix. Nous venons ainsi de lancer cette phase de recrutement début avril.</p>
<hr/>
<h2>Conclusion</h2>
<p>Nous espérons que les résolutions qui vous sont proposées recevront votre agrément et que vous voudrez bien donner à la Présidente quitus de sa gestion pour l’exercice écoulé.</p>
<p>Rédigé collectivement par l'équipe de Yaal Coop,
Signé par Brunélie Lauret, Présidente de Yaal Coop</p>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Transparence et réactivité : nos bonnes pratiques pour la sécurité de vos systèmes</title>
        <link href="https://bearstech.com/societe/blog/transparence-et-reactivite-nos-bonnes-pratiques-pour-la-securite-de-vos-systemes" />
        <id>https://bearstech.com/societe/blog/transparence-et-reactivite-nos-bonnes-pratiques-pour-la-securite-de-vos-systemes</id>
        <updated>2024-05-12T16:54:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>emazurier</name>
        </author>
    </entry>
    <entry>
        <title>Python : Scanner un document sous Windows avec l&#39;API WIA</title>
        <link href="https://blog.flozz.fr/2024/04/17/python-scanner-un-document-sous-windows-avec-lapi-wia/" />
        <id>https://blog.flozz.fr/2024/04/17/python-scanner-un-document-sous-windows-avec-lapi-wia/</id>
        <updated>2024-04-18T08:06:17Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Pour les besoins d’un projet sur lequel je travaille actuellement, je dois accéder à des scanners pour numériser des documents depuis un script Python sur différentes plateformes (principalement Windows et macOS). Aujourd’hui je vais donc vous parler de la numérisation de document sous Windows via l’API WIA (Windows Image Acquisition) à l’aide de la bibliothèque pywin32.</p>
<a href="https://news.humancoders.com/t/python/items/21143-python-scanner-un-document-sous-windows-avec-l-api"><img src="https://blog.flozz.fr/cover/2024/winscanpy.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/21143-python-scanner-un-document-sous-windows-avec-l-api#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/21143-python-scanner-un-document-sous-windows-avec-l-api">Python : Scanner un document sous Windows avec l'API WIA</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>FLOZz</name>
        </author>
    </entry>
    <entry>
        <title>JavaScript hack update</title>
        <link href="https://www.olivierpons.fr/2024/04/11/javascript-hack-update/" />
        <id>https://www.olivierpons.fr/2024/04/11/javascript-hack-update/</id>
        <updated>2024-04-12T00:48:37Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Mise à jour en pur JavaScript hacks</h1>
<p>Voici une petite mise à jour en vanilla JS qui fait la même chose que ce que j’ai mis <a href="https://www.olivierpons.fr/2018/03/19/javascript-hacks/" rel="noopener" target="_blank">ici</a>.</p>
<pre style="font-size: 70%; line-height: normal;">function emptyBody() {
    document.body.innerHTML = '';
}
function getRandomInt(max) {
    return Math.floor(Math.random() * Math.floor(max));
}
function addNewAvatar() {
    let curr = getRandomInt(5000);
    return function() {
        const img = document.createElement('img');
        img.src = `https://avatars.githubusercontent.com/u/${curr}`;
        img.style.maxWidth = '50px';
        img.style.display = 'inline-block';
        img.style.float = 'left';
        img.style.margin = '0';
        img.style.padding = '0';
        document.body.appendChild(img);
        curr += (1 + getRandomInt(3));
        setTimeout(addNewAvatar(), 100);
    };
}
emptyBody();
setTimeout(addNewAvatar(), 100);</pre>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Gestion de la mémoire Redis : comprendre et résoudre l’erreur ‘OOM command not allowed’ sur le long terme</title>
        <link href="https://bearstech.com/societe/blog/gestion-de-la-memoire-redis-comprendre-et-resoudre-lerreur-oom-command-not-allowed-sur-le-long-terme" />
        <id>https://bearstech.com/societe/blog/gestion-de-la-memoire-redis-comprendre-et-resoudre-lerreur-oom-command-not-allowed-sur-le-long-terme</id>
        <updated>2024-04-05T17:03:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>vcaron</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;hiver 2024</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2024" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2024</id>
        <updated>2024-03-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://gitlab.com/sblondon/mozsearch-pypi">PyPI search</a></h2>
<p><em>Greffon Firefox pour chercher des bibliothèques Python hébergées par PyPI (pypi.org)</em></p>
<ul>
<li>Remplacement des occurences de « Pypi » par « PyPI »</li>
<li>Publication d'une nouvelle version (1.0.1)</li>
</ul>
<h2><a href="https://github.com/sharkdp/bat">Bat</a></h2>
<p><em>Un clone de cat(1) avec coloration syntaxique et intégration Git</em></p>
<ul>
<li><a href="https://github.com/sharkdp/bat/pull/2838">Affiche quel est le thème par défaut</a> lors de l'utilisation du paramètre <code>--list-themes</code></li>
<li>Ajout d'une capture d'écran sur <a href="https://screenshots.debian.net/package/bat">screenshots.debian.net</a> illustrant l'utilisation du paramètre <code>--list-themes</code></li>
</ul>
<h2><a href="https://github.com/jhunt/hatop">HATop</a></h2>
<p><em>Un client ncurses interactif pour HAProxy</em></p>
<ul>
<li><a href="https://github.com/jhunt/hatop/pull/17">Correction d'une alerte sur la syntaxe</a> survenant avec Python 3.12, basé sur un <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1061802">rapport de bogue Debian</a></li>
</ul>
<h2><a href="https://virt-manager.org/">Virt-Manager</a></h2>
<p><em>Client lourd pour gérer des machines virtuelles</em></p>
<ul>
<li>Correction et ajouts de traduction en français sur <a href="https://translate.fedoraproject.org/projects/virt-manager/virt-manager/">https://translate.fedoraproject.org/projects/virt-manager/virt-manager/</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/823">Correctif sur la coercition de SelectField</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/824">Correctif pour la compatibilité avec Babel 2.14</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/830">Conciergerie</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Bibliothèque python de gestion des identités et des accès</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/614">Améliorations sur la documentation de RFC7523</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/164">Implémentation de la souscription d’utilisateurs par OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/165">Configuration de la journalisation au format de Python</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/166">Mise à jour vers HTMX 1.9.11</a></li>
</ul>
<h2><a href="https://matrix.org">Matrix</a></h2>
<p><em>Une nouvelle base de communication ouverte, intéropérable, décentralisée et en temps réel</em></p>
<ul>
<li><a href="https://github.com/matrix-org/matrix-spec-proposals/pull/4098">Proposition de MSC4098 pour le support de SCIM</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Winter 2024 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2024" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2024</id>
        <updated>2024-03-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://gitlab.com/sblondon/mozsearch-pypi">PyPI search</a></h2>
<p><em>Firefox plug-in to search Python libraries hosted at PyPI (pypi.org)</em></p>
<ul>
<li>Replace Pypi occurrences by PyPI one</li>
<li>Release a new version (1.0.1)</li>
</ul>
<h2><a href="https://github.com/sharkdp/bat">Bat</a></h2>
<p><em>A cat(1) clone with syntax highlighting and Git integration</em></p>
<ul>
<li><a href="https://github.com/sharkdp/bat/pull/2838">Display which theme is the default one</a> with <code>--list-themes</code> parameter</li>
<li>Add a screenshot about the <code>--list-themes</code> parameter usage on <a href="https://screenshots.debian.net/package/bat">screenshots.debian.net</a></li>
</ul>
<h2><a href="https://github.com/jhunt/hatop">HATop</a></h2>
<p><em>An Interactive ncurses Client for HAProxy</em></p>
<ul>
<li><a href="https://github.com/jhunt/hatop/pull/17">Fix syntax warning</a> occurring with Python 3.12, based on a <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1061802">Debian bug report</a></li>
</ul>
<h2><a href="https://virt-manager.org/">Virt-Manager</a></h2>
<p><em>Desktop user interface for managing virtual machines</em></p>
<ul>
<li>Fix and add french translations on <a href="https://translate.fedoraproject.org/projects/virt-manager/virt-manager/">https://translate.fedoraproject.org/projects/virt-manager/virt-manager/</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/823">SelectField coercion fix</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/824">Babel 2.14 compatibility fix</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/830">Janitoring</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Identity and Access management library for python</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/614">RFC7523 documentation improvements</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Lightweight identity and authorization management software</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/164">OIDC User registration implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/165">Python logging configuration format support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/166">HTMX 1.9.11 upgrade</a></li>
</ul>
<h2><a href="https://matrix.org">Matrix</a></h2>
<p><em>A new basis for open, interoperable, decentralised real-time communication</em></p>
<ul>
<li><a href="https://github.com/matrix-org/matrix-spec-proposals/pull/4098">MSC4098 proposal for SCIM support</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>ssh : les nouveaux types de cryptographies et clés pour plus de sécurité</title>
        <link href="https://www.olivierpons.fr/2024/03/20/ssh-les-nouveaux-types-de-cryptographies-et-cles-pour-plus-de-securite/" />
        <id>https://www.olivierpons.fr/2024/03/20/ssh-les-nouveaux-types-de-cryptographies-et-cles-pour-plus-de-securite/</id>
        <updated>2024-03-20T10:14:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>GitHub et GitLab ont adopté des normes de sécurité SSH plus récentes et plus robustes pour renforcer la sécurité des connexions.</p>
<p>En remplacement, GitHub a introduit les clés hôtes ECDSA et Ed25519, qui sont basées sur la cryptographie à courbe elliptique, offrant ainsi de meilleures caractéristiques de sécurité pour des augmentations modestes de taille et de calcul. </p>
<p>Aujourd’hui, on recommande l’utilisation de clés SSH ED25519, qui sont plus sécurisées et devraient être disponibles sur n’importe quel système. Bien sûr quand on parle de système Linux on est sûr qu’elles sont déjà présentes.</p>
<p>Il est essentiel de générer des paires de clés SSH sûres et de les configurer correctement. Par défaut une clé de 1024 bits est générée, <strong>il faut donc impérativement changer la taille de la clé par au minimum 4096</strong> :</p>
<blockquote>
<h3><code>ssh-keygen -t rsa -b 4096</code></h3>
</blockquote>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Do not use requirements.txt</title>
        <link href="https://zestedesavoir.com/billets/4637/do-not-use-requirements-txt/" />
        <id>https://zestedesavoir.com/billets/4637/do-not-use-requirements-txt/</id>
        <updated>2024-03-01T18:22:38Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Et pourquoi pas ?
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Formation complète de scraping avec Python</title>
        <link href="https://www.youtube.com/watch?v=sOAZpHDEdkg" />
        <id>https://www.youtube.com/watch?v=sOAZpHDEdkg</id>
        <updated>2024-02-17T14:08:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Découvrez 10h de formation gratuite sur le scraping avec Python.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/21014-formation-complete-de-scraping-avec-python#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/21014-formation-complete-de-scraping-avec-python">Formation complète de scraping avec Python</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Thibault Houdon</name>
        </author>
    </entry>
    <entry>
        <title>Modification de la sortie de bat</title>
        <link href="https://ascendances.wordpress.com/2024/02/11/modification-de-la-sortie-de-bat/" />
        <id>https://ascendances.wordpress.com/2024/02/11/modification-de-la-sortie-de-bat/</id>
        <updated>2024-02-11T21:39:54Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://github.com/sharkdp/bat"><code>bat</code></a> permet d’afficher le contenu d’un fichier en activant la coloration syntaxique par défaut. <code>bat</code> permet aussi de changer le thème (<code>DarkNeon</code> dans les captures d’écran suivant) ou les informations affichées.</p>
<p>Avec le code Python suivant contenu dans un fichier nommé <code>futilite.py</code> :</p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: python; title: ; notranslate">
def sujet_principal(sujets):
    """d'après https://fr.wikipedia.org/wiki/Loi_de_futilit%C3%A9_de_Parkinson"""
    ordre = sorted(sujets, key=lambda sujet: sujet.importance)    
    return ordre[0]
</pre></div>
<p>L’ensemble des décorations possibles est affiché avec le paramètre <code>full</code>.</p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: plain; title: ; notranslate">
bat futilite.py --style="full"
</pre></div>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-full-base.png"><img alt="" class="wp-image-2959" height="177" src="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-full-base.png?w=831" width="831"/></a></figure>
<p>Au contraire, la version sans décoration (et donc celle qui est le plus proche du comportement de <code>cat</code>) s’obtient avec le style <code>plain</code>. C’est aussi équivalent à l’utilisation de <a href="https://pygments.org/">pygmentize</a> avec un alias (cf. <a href="https://ascendances.wordpress.com/2021/02/21/coloration-syntaxique-de-votre-code-avec-pygments/">un article précédent</a>).</p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: plain; title: ; notranslate">
bat futilite.py --style="plain"
</pre></div>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-plain.png"><img alt="" class="wp-image-2958" height="86" src="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-plain.png?w=733" width="733"/></a><figcaption class="wp-element-caption">Plusieurs blocs sont activables ou non en ajoutant des éléments au paramètre <code>style</code>. La liste des éléments est disponible dans la page de man. Par exemple, <code>changes</code> pour afficher des différences Git, <code>header-filesize</code> pour afficher la taille du fichier, <code>rule</code> pour afficher une ligne entre deux fichiers, etc.).</figcaption></figure>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-full-1.png"><img alt="" class="wp-image-2965" height="226" src="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-full-1.png?w=821" width="821"/></a></figure>
<p>Par exemple, si on veut limiter l’affichage aux numéros de ligne, à la taille du fichier (et son contenu évidemment) :</p>
<div class="wp-block-syntaxhighlighter-code"><pre class="brush: plain; title: ; notranslate">
bat futilite.py --style="numbers, header-size"
</pre></div>
<figure class="wp-block-image size-large"><a href="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-numbers-filesize-1.png"><img alt="" class="wp-image-2966" height="109" src="https://ascendances.wordpress.com/wp-content/uploads/2024/02/bat-numbers-filesize-1.png?w=778" width="778"/></a></figure>
<p>Personne n’ayant envie de retaper ce paramètre <code>style</code> en permanence, il est enregistrable dans le fichier <code>$HOME/.config/bat/config</code> (le chemin est modifiable par une variable d’environnement). Un contenu d’exemple est montré dans le <a href="https://github.com/sharkdp/bat#format">README.md de bat</a>.</p>
            </div>
        </content>
        <author>
            <name>ascendances</name>
        </author>
    </entry>
    <entry>
        <title>Comment écrire un moteur de recherche en 80 lignes de Python ?</title>
        <link href="https://www.alexmolas.com/2024/02/05/a-search-engine-in-80-lines.html" />
        <id>https://www.alexmolas.com/2024/02/05/a-search-engine-in-80-lines.html</id>
        <updated>2024-02-09T11:36:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Comment écrire un moteur de recherche en 80 lignes de Python ? Cet article décrit les principaux composants d’un moteur de recherche : le Crawler, l’Inverted index et le Ranker.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/21003-comment-ecrire-un-moteur-de-recherche-en-80-lignes#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/21003-comment-ecrire-un-moteur-de-recherche-en-80-lignes">Comment écrire un moteur de recherche en 80 lignes de Python ?</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Vincent Daubry</name>
        </author>
    </entry>
    <entry>
        <title>Présentation de certaines fonctions built-in et itertools</title>
        <link href="https://zestedesavoir.com/billets/4608/presentation-de-certaines-fonctions-built-in-et-itertools/" />
        <id>https://zestedesavoir.com/billets/4608/presentation-de-certaines-fonctions-built-in-et-itertools/</id>
        <updated>2024-01-23T11:05:05Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Je vous présente les éléments que j'utilise les plus régulièrement quand je développe en python.
            </div>
        </content>
        <author>
            <name>Melcore</name>
        </author>
    </entry>
    <entry>
        <title>Sécuriser et optimiser le build des images Docker pour vos applications.</title>
        <link href="https://bearstech.com/societe/blog/securiser-et-optimiser-le-build-des-images-docker-pour-vos-applications" />
        <id>https://bearstech.com/societe/blog/securiser-et-optimiser-le-build-des-images-docker-pour-vos-applications</id>
        <updated>2024-01-11T09:28:39Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                
            </div>
        </content>
        <author>
            <name>emazurier</name>
        </author>
    </entry>
    <entry>
        <title>Recréez le jeu classique Pong en Python</title>
        <link href="https://dev.to/ssaurel/creating-the-classical-pong-game-in-python-with-a-tkinter-ui-1djl" />
        <id>https://dev.to/ssaurel/creating-the-classical-pong-game-in-python-with-a-tkinter-ui-1djl</id>
        <updated>2024-01-05T11:24:34Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet article propose de détailler la création pas à pas du classique jeu de Pong en Python avec une UI s’appuyant sur la bibliothèque Tkinter.</p>
<a href="https://news.humancoders.com/t/python/items/20913-recreez-le-jeu-classique-pong-en-python"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hkEpuKCK--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m5k5czn4mcmeymukndgw.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20913-recreez-le-jeu-classique-pong-en-python#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20913-recreez-le-jeu-classique-pong-en-python">Recréez le jeu classique Pong en Python</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>ssaurel</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;automne 2023</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2023" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2023</id>
        <updated>2023-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/153">Correction d'un bug sur la suppression d'utilisateurs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/154">Mise à jour vers htmx 1.9.6</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/155">Support de Python 3.12</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/156">Cardinalité des modèles basée sur la norme SCIM</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/157">Méthodes additionnelles d’identification pour les jetons de rafraîchissement OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/158">Support des bases de données SQL</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/159">Mise à jour vers htmx 1.9.9</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/160">Désactivation de htmx lors de l’authentification OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/161">Gestion des pages d’erreur avec htmx</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/162">Conversion des images en webp</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/163">Mise à jour vers Flask 3</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/739">Réusinage de <code>SelectField</code></a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/797">Implementation de validateurs <code>readonly</code> et <code>disabled</code></a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/798">Migration de setuptools à hatch</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/808">Affichage des valeurs dans la représentation de Flags</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/812">Corrections sur des exemples en documentation</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/812">Réusinage de tests unitaires</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/818">Support de python 3.12</a></li>
</ul>
<h2><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h2>
<p><em>Intégration de WTForms dans Flask</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/573">Correction de la protection CSRF sur les blueprints imbriqués</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/576">Migration de setuptools à hatch</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.1.2">Publication de la version 1.1.2</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.2.0">Publication de la version 1.2.0</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/578">Corrections d'un bug sur les validateurs de champs de fichiers</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.2.1">Publication de la version 1.2.1</a></li>
</ul>
<h2><a href="https://anymail.dev/">django-anymail</a></h2>
<p><em>Anymail: Intégration de fournisseurs d'e-mails transactionnels dans Django</em></p>
<ul>
<li><a href="https://github.com/anymail/django-anymail/pull/321">Mise-à-jour du fournisseur Brevo.com provider (précédemment Sendinblue)</a></li>
</ul>
<h2><a href="https://github.com/spiral-project/ihatemoney">ihatemoney</a></h2>
<p><em>Une application web simple de gestion de budget</em></p>
<ul>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1243">Migration de <code>setup.cfg</code> à <code>pyproject.toml</code></a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1248">Support de WTForms 3.1</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1255">Support de Python 3.12</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1258">Migration de setuptools vers hatch</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Bibliothèque python de gestion des identités et des accès</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/590">Support de python 3.12</a></li>
</ul>
<h2><a href="https://github.com/level12/flask-webtest">flask-webtest</a></h2>
<p><em>Utilitaires de test d'applications Flask avec WebTest</em></p>
<ul>
<li><a href="https://github.com/level12/flask-webtest/pull/21/">Améliorations sur la documentation</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Autumn 2023 FOSS contributions from by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2023" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2023</id>
        <updated>2023-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/153">Fix user deletion bug</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/154">Bump to htmx 1.9.6</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/155">Python 3.12 support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/156">Model cardinality based on SCIM specifications</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/157">Additional refresh token grant authentication methods</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/158">SQL backend implementation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/159">Bump to htmx 1.9.9</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/160">Disable htmx during OIDC authentication</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/161">Handle error pages with htmx</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/162">Convert images in webp</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/163">Update to Flask 3</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/739"><code>SelectField</code> refactoring</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/797">Implementation of <code>readonly</code> and <code>disabled</code> validators</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/798">Migrate from setuptools to hatch</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/808">Display values in Flag repr</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/812">Fix documentation examples</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/812">Unit test refactoring</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/818">Python 3.12 support</a></li>
</ul>
<h2><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h2>
<p><em>Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/573">Fix CSRF protection on nested blueprints</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/576">Migrate from setuptools to hatch</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.1.2">Release 1.1.2</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.2.0">Release 1.2.0</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/578">Fix a file validator bug</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.2.1">Release 1.2.1</a></li>
</ul>
<h2><a href="https://anymail.dev/">django-anymail</a></h2>
<p><em>Anymail: Django email integration for transactional ESPs</em></p>
<ul>
<li><a href="https://github.com/anymail/django-anymail/pull/321">Update brevo.com provider (formerly Sendinblue)</a></li>
</ul>
<h2><a href="https://github.com/spiral-project/ihatemoney">ihatemoney</a></h2>
<p><em>A simple shared budget manager web application</em></p>
<ul>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1243"><code>setup.cfg</code> to <code>pyproject.toml</code> migration</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1248">WTForms 3.1 support</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1255">Python 3.12 support</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1258">Setuptools to hatch migration</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Identity and Access management library for python</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/590">Python 3.12 support</a></li>
</ul>
<h2><a href="https://github.com/level12/flask-webtest">flask-webtest</a></h2>
<ul>
<li>
<p>Utilities for testing Flask applications with WebTest*</p>
</li>
<li>
<p><a href="https://github.com/level12/flask-webtest/pull/21/">Documentation improvements</a></p>
</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Canaille, un système léger de gestion d’identité et d’accès</title>
        <link href="https://yaal.coop/blog/canaille-nlnet-pytest-iam" />
        <id>https://yaal.coop/blog/canaille-nlnet-pytest-iam</id>
        <updated>2023-11-28T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Depuis un certain temps l’équipe de Yaal Coop travaille sur Canaille, un logiciel de gestion d’identité et d’accès.
Nous profitons de la fin de travaux financés par la fondation NLNet pour vous raconter l’histoire autour de Canaille.</p>
<p><a href="https://canaille.yaal.coop"><img alt="Canaille" src="https://yaal.coop/media/img/canaille.webp"/></a></p>
<h2>Au début étaient les annuaires</h2>
<p>À Yaal Coop (comme presque partout ailleurs) nous utilisons une palette d’outils qui nous permettent de travailler ensemble.
Emails, fichiers, carnets de contacts, gestion de projet, suivi du temps, comptabilité, intégration continue, collecte de rapports de bugs… la liste est longue.
Pour des raisons de praticité (et de sécurité) on cherche généralement à connecter une telle collection d’outils à un logiciel central qui se charge de la gestion des utilisateur·ices et de leurs accès.
Traditionnellement, c’est LDAP<sup id="sf-canaille-nlnet-pytest-iam-1-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-1" title="enfin, un logiciel qui implémente LDAP, ici je parle indifféremment du protocole ou de ses implémentations">1</a></sup> qui est utilisé pour cet usage, on parle alors d’annuaire.</p>
<p>Si un outil est connecté à un annuaire, vous n’avez pas besoin de vous y créer un compte, vous pouvez vous connecter en utilisant votre mot de passe habituel, celui que vous avez renseigné dans l’annuaire.
C’est pratique pour vous puisque vous n’avez qu’un unique mot de passe à retenir <em>(ou à oublier)</em>, on parle généralement d’inscription unique <em>ou Single Sign On (<abbr>SSO</abbr>)</em>.
C’est aussi pratique pour les personnes qui gèrent les comptes dans votre organisation, puisqu’elles peuvent créer et révoquer des comptes utilisateur·ices une seule fois pour tous les outils à la fois.</p>
<p>LDAP, c’est vieux et c’est robuste. Pour des logiciels, ce sont des qualités.
Les quelques décennies d’expérience de LDAP en font une technologie éprouvée et compatible avec un énorme choix de logiciels.</p>
<p>Mais LDAP, c’est aussi compliqué et austère.
C’est une base de donnée <em>en arbre</em> qui ressemble à peu d’autres choses, la documentation est éparse et absconse, les conventions sont curieuses, pleines d’acronymes angoissants, l’outillage est rare…
Et puis c’est conçu pour les données qui sont lues souvent mais écrites rarement.
Les modèles de données utilisables dans LDAP sont eux aussi peu évolutifs.
Généralement quelques uns sont fournis d’office et permettent de manipuler des attributs de base sur des utilisateur·ices et des groupes.
Et si on veut que son système puisse gérer d’autres attributs comme les couleurs préférées, alors il faut écrire ses propres modèles de données, et on a intérêt à être sûr de soi puisqu’aucun mécanisme de mise à jour des schémas ou de migration des données n’est prévu<sup id="sf-canaille-nlnet-pytest-iam-2-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-2" title="du moins avec OpenLDAP">2</a></sup>.
Si on souhaite ensuite partager ces modèles de données, alors il est conseillé de s’enregistrer à l’<a href="https://iana.org">IANA</a><sup id="sf-canaille-nlnet-pytest-iam-3-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-3" title="ce que nous avons fait, notre numéro à l’IANA est le 56207">3</a></sup>, et de fournir une référence en ligne de ses schémas.
Quand on se plonge dans l’univers de LDAP, on a l’impression qu’une fois mises en place, les installations ne bougent pas pendant des années ;
et donc les personnes qui ont la connaissance fuient l’austérité de cette technologie sans avoir à s’y ré-intéresser (puisque <em>ça fonctionne</em>), et sans trop documenter leurs aventures.
J’exagère à peine, si on compare<sup id="sf-canaille-nlnet-pytest-iam-4-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-4" title="d’accord, la comparaison est fallacieuse puisque ces différentes bases de données ne répondent pas aux mêmes besoins, mais l’ordre de grandeur est révélateur de l’intérêt autour de ces technologies">4</a></sup> le nombre de questions sur <a href="https://stackoverflow.com">stackoverflow</a>, pour <a href="https://stackoverflow.com/questions/tagged/ldap">ldap</a> on en dénombre environ 1000 tandis que <a href="https://stackoverflow.com/questions/tagged/postgresql">postgresql</a> ou <a href="https://stackoverflow.com/questions/tagged/mongodb">mongodb</a> en comptent environ 14 000 et <a href="https://stackoverflow.com/questions/tagged/mysql">mysql</a> 45 000.</p>
<h2>Puis vint l’authentification unique</h2>
<p>Lors de temps de bénévolat à <a href="https://supercoop.fr">Supercoop</a><sup id="sf-canaille-nlnet-pytest-iam-5-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-5" title="le supermarché coopératif de l’agglomération bordelaise">5</a></sup>, nous avons notamment travaillé à installer, comme pour chez nous, plusieurs outils numériques de collaboration.
Évidemment tous les outils étaient branchés sur un annuaire LDAP.
Nous nous sommes rendus compte que l’équipe dite de <em>gestion des membres</em>, passait un certain temps à traiter des demandes de réinitialisation de mot de passe, à aider des personnes qui échouaient à utiliser les outils dès les premières étapes de connexion.
Ce constat nous a donc poussé à chercher des outils (libres, évidemment) d’authentification unique et de gestion d’utilisateur·ices, en complément ou remplacement de l’annuaire.
Ce que l’authentification unique <em>ou Single Login Identification (<abbr>SLI</abbr>)</em> apporte au SSO fourni par LDAP, c’est que les utilisateur·ices peuvent naviguer entre les outils sans avoir à s’identifier à nouveau.
On peut passer de l’interface mail à son calendrier en ligne sans repasser par l’écran d’identification, tandis qu’avec un simple annuaire, il aurait été nécessaire d’entrer son mot de passe une fois pour chaque outil.
Pour un public non technophile, c’est l’opportunité de se passer de quelques écrans techniques, et limiter les sources d’erreur et de frustration.</p>
<p>Actuellement les protocoles de prédilection pour faire du SLI sont OAuth2 et OpenID Connect (<abbr>OIDC</abbr>)<sup id="sf-canaille-nlnet-pytest-iam-6-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-6" title="par abus de langage, je dirai simplement OIDC">6</a></sup>. On note qu’il existe d’autres standards, plus historiques ou bien plus orientés vers les grosses organisations, tels <a href="https://fr.wikipedia.org/wiki/Security_assertion_markup_language">SAML</a> ou <a href="https://fr.wikipedia.org/wiki/Central_Authentication_Service">CAS</a>.
Les normes OAuth2 et OIDC sont modernes mais bénéficient d’une dizaine d’années de retours d’expérience.
Les outils et les documentations sont nombreuses, la communauté est active, et les standards évoluent en ce moment même grâce au <a href="https://datatracker.ietf.org/wg/oauth/about/">groupe de travail <em>oauth</em></a> de l’<abbr>IETF</abbr><sup id="sf-canaille-nlnet-pytest-iam-7-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-7" title="l’« Internet Engineering Task Force » un organsime étasunien de développement et de promulgation de standards">7</a></sup>.
Mais là encore tout n’est pas rose et OIDC vient avec son lot de difficultés.</p>
<p>Tout d’abord, OAuth2 et OIDC c’est environ <a href="https://canaille.readthedocs.io/en/latest/specifications.html#state-of-the-specs-in-Canaille">30 standards complémentaires</a>, dont certains contredisent et apportent des corrections sur des standards antérieurs.
Tous ne sont pas pertinents dans l’usage que nous visons, mais ne serait-ce que simplement <em>comprendre</em> le fonctionnement de ceux qui nous intéressent demande déjà du temps et de la réflexion.
Les implémentations d’OIDC — par les logiciels de gestions d’utilisateur·ices, ou par les outils qui s’y branchent — sont généralement partielles, et parfois bugguées.
Pour ne rien arranger, les gros acteurs de l’industrie prennent délibérément des libertés avec les standards et forcent le développement de spécificités pour être compatibles avec leurs logiciels.<sup id="sf-canaille-nlnet-pytest-iam-8-back"><a class="simple-footnote" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-8" title="Ils peuvent aussi êtres moteurs de nouvelles améliorations, comme RFC7628 ou RFC9068 qui furent des usages avant d’être des standards.">8</a></sup></p>
<p>Mais revenons à nos moutons. Pour Supercoop nous souhaitions trouver un outil qui soit d’une grande simplicité à plusieurs points de vue :</p>
<ul>
<li>pour les utilisateur·ices : les coopérateur·ices du magasin. L’utilisation doit se faire sans aucune connaissance technique préalable, et sans assistance ;</li>
<li>pour l’équipe de <em>gestion des membres</em> du magasin. Nous voulions un outil simple à prendre en main.
  Un apprentissage de l’outil est envisageable mais non souhaitable.
  En effet le magasin fonctionnant grâce à la participation de bénévoles, il y a un enjeu à ce que le temps passé soit le moins rébarbatif possible, afin de ne décourager personne.</li>
<li>enfin pour l’équipe <em>informatique</em>, il y a là aussi un enjeu de simplicité.
  Si les outils déployés pour le magasin requièrent trop de connaissances, nous aurons des problèmes pour trouver des gens compétents pour nous aider.
  Et la nature de la participation du magasin fait que les coopérateur·ices contribuent ponctuellement, tournent souvent, et n’ont pas nécessairement le temps d’apprendre toute la pile technique mise en œuvre.
  Idéalement, l’équipe informatique devrait pouvoir administrer l’outil que nous recherchons avec une connaissance superficielle des protocoles concernés.
  <em>Et vues les descriptions que j’ai faites de LDAP et OIDC, vous commencez à cerner une partie du problème</em>.</li>
</ul>
<p><a href="https://canaille.readthedocs.io/en/latest/specifications.html#comparison-with-other-providers">Notre recherche</a> nous a montré qu’il existait une quinzaine d’outils pouvant répondre aux besoins que nous avons identifiés.
Pour autant, aucun outil ne nous semblait cocher toutes les cases.
En fait, par leur nature, les outils de gestion d’identité et d’autorisations <em>ou Identity and Authorization Management (<abbr>IAM)</abbr></em> sont destinés à de grosses organisations, qui peuvent donc s’offrir les services de personnes qualifiées pour s’en occuper.
Ce sont donc des logiciels lourds mais puissants, supportant beaucoup de protocoles qui ne nous concernent pas, requiérant une certaine technicité pour l’installation, la maintenance ou la gestion.
Motivés par notre curiosité nous avons fini par bricoler quelque chose dans notre coin.</p>
<h2>Canaille</h2>
<p>Quelques temps après, notre prototype a grossi et a donné <a href="https://canaille.yaal.coop">Canaille</a>.</p>
<h3>Les fonctionnalités</h3>
<p>Canaille est un logiciel qui permet de gérer des utilisateur·ices et des groupes d’utilisateur·ices, de créer, modifier et administrer des comptes, de réinitialiser des mots de passes perdus, d’inviter des nouveaux utilisateur·ices.
En plus de ça, Canaille implémente OIDC et fournit donc une authentification unique aux utilisateur·ices vers d’autres outils. Son interface est personnalisable et … c'est tout.
Nous tâchons de garder le périmètre fonctionnel de Canaille assez restreint pour qu'il reste simple.</p>
<p>Canaille peut être utilisé pour :</p>
<ul>
<li>apporter une interface web épurée de gestion des comptes utilisateur·ices au dessus d’un annuaire LDAP.
  L’outillage autour de LDAP étant comme on l’a dit plutôt épars, Canaille peut être utilisé pour modifier facilement un profil utilisateur·ice ou réinitialiser un mot de passe perdu.</li>
<li>amener du SLI sur un annuaire LDAP.
  Si vous avez historiquement un annuaire LDAP et que vous voulez moderniser votre pile logicielle avec une couche d’authentification unique, Canaille peut s’intégrer discrètement au-dessus de votre installation existante sans rien modifier,
  et vous laisser le temps de prévoir – ou pas – une migration.</li>
<li>développer des applications utilisant OIDC.
  Si, comme nous, vous faites du développement logiciel et travaillez régulièrement sur des applications nécessitant une connexion OIDC, alors vous pouvez utiliser Canaille dans votre environnement de développement.
  Canaille étant très léger, c'est désormais pour nous la solution de choix comme IAM pour travailler sur nos applications.</li>
<li>tester des applications utilisant OIDC.
  Nous utilisons aussi Canaille dans des suites de tests unitaires python, grâce à <a href="https://pytest-iam.readthedocs.io/en/latest/">pytest-iam</a>.
  Ce greffon de pytest embarque Canaille, le prépare et l’instancie pour que vos suites de tests puissent effectuer une réelle connexion OIDC.</li>
</ul>
<h3>Les choix techniques</h3>
<p>Canaille est un logiciel écrit en python, avec <a href="https://flask.palletsprojects.com/en/3.0.x/">flask</a> pour le côté serveur et <a href="https://fomantic-ui.com/">fomantic-ui</a> et <a href="https://htmx.org">htmx</a> pour la partie client utilisateur·ice.
Nous apprécions la simplicité de python et celle de flask et croyons sincèrement que ce sont autant de freins en moins à la participation d’éventuels contributeur·ices.
Nous avons été sidérés par notre découverte récente de HTMX, qui en deux mots nous permet de créer des pages web dynamiques sans plus écrire de Javascript.
Un langage en moins dans un projet c'est autant de complexité en moins.</p>
<p>Sous le capot, Canaille peut se brancher au choix à un annuaire LDAP ou à une base de données SQL.</p>
<h3>Les techniques de développement</h3>
<p>Nous utilisons Canaille en production, à Supercoop donc où il est utilisé pour gérer environ 1800 membres, mais aussi chez nous à Yaal Coop et au sein de notre offre mutualisée de services <a href="https://nubla.fr">Nubla</a>, et sur des instances dédiées Nubla Pro.
Cette large base d’utilisateur·ices nous permet de récolter des retours d’expérience, et nous améliorons le logiciel au fur et à mesure des besoins.</p>
<p>Canaille suit le principe du développement dirigé par les tests, <em>ou Test Driven Development (TDD)</em>, dans la mesure du possible.
<a href="https://fr.wikipedia.org/wiki/Couverture_de_code">La couverture du code</a> est de 100% <em>(branches comprises)</em>, et c’est un pré-requis pour toute contribution.
En plus d’avoir confiance dans nos tests, cela nous a permis à plusieurs reprises de simplement supprimer du code qui n’était plus utilisé, et simplifier d’autant le projet.
On débusque plus facilement les bugs quand il y a moins de code.</p>
<p>Canaille utilise tous les analyseurs et formatteurs de code source modernes, au sein de <a href="https://gitlab.com/yaal/Canaille/-/blob/main/.pre-commit-config.yaml">pre-commit</a>, et les test unitaires sont joués sur toutes les versions de Python officiellement supportées.</p>
<p>Enfin la traduction de l’interface de Canaille se fait de manière communautaire sur <a href="https://hosted.weblate.org/engage/Canaille/?utm_source=widget">weblate</a>.</p>
<h3>Contributions</h3>
<p>Comme la plupart des logiciels modernes, Canaille réutilise des bibliothèques logicielles existantes pour que nous n’ayions pas à ré-inventer ce que d’autres ont déjà fait.</p>
<p>Lorsque nous rencontrons des erreurs dans ces bibliothèques, nous suivons une stratégie qui consiste à implémenter les corrections à la fois dans Canaille et dans les logiciels.
D’une part nous amenons donc les corrections dans Canaille, de manière temporaire et efficace.
Mais tout ce code que nous écrivons nous-même est un fardeau de maintenance à venir, nous tâchons donc en parallèle de proposer des solutions mieux conçues aux mainteneur·euses desdites bibliothèques, en discutant avec eux en amont.
C'est pour nous la garantie que les briques logicielles sur lesquelles nous nous appuyons sont pérennes, et c’est un moyen de contribuer à cet écosystème nécessaire qu’est celui du logiciel libre.</p>
<p>Par ailleurs lorsque nous souhaitons des fonctionnalités supplémentaires dans ces bibliothèques, nous expliquons nos motivations aux mainteneur·euses et parfois proposons des implémentations. Nous avons par exemple développé le support des spécifications OIDC <a href="https://github.com/lepture/authlib/pull/505">RFC7591</a> et <a href="https://github.com/lepture/authlib/pull/586">RFC9068</a> dans <a href="https://github.com/lepture">authlib</a>, une brique utilisée pour la partie OIDC de Canaille.</p>
<p>Le résultat de ces efforts est visible dans <a href="https://yaal.coop/blog/tag/contributions">nos articles trimestriels</a> de contributions à des logiciels libres.</p>
<p>Le hasard des contributions nous a amené à partager la maintenance de certaines des bibliothèques que nous utilisons, comme <a href="https://github.com/wtforms/wtforms">wtforms</a> qui permet de gérer les formulaires dans Canaille, ou encore <a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a> et <a href="https://github.com/jumbojett/OpenID-Connect-PHP">OpenIDConnect-PHP</a> qui permettent à <a href="https://nextcloud.com">nextcloud</a> (le gestionnaire de fichiers proposé par Nubla) de se connecter à Canaille.</p>
<p>Nous sponsorisons aussi modestement tous les mois les mainteneur·ices de <a href="https://github.com/lubber-de">fomantic-ui</a> et <a href="https://github.com/lepture">authlib</a>.</p>
<h2>L’aide de la fondation NLNet</h2>
<p>Canaille a été développé pour répondre aux besoins spécifiques que nous avons rencontrés : à l’origine Canaille s’interfaçait donc seulement avec des annuaires LDAP.
L’écosystème évoluant, nous nous sommes aperçus que de plus en plus de logiciels étaient capables de communiquer avec OIDC en plus de LDAP.
In fine, si plus aucun des logiciels que nous utilisons ne dépend directement de LDAP, alors nous pouvons envisager un outil de remplacement avec lequel nous nous sentons plus à l’aise.
Pour aller dans cette direction, nous avons sollicité fin 2022 l’aide de 7 000€ au fond <strong>NGI Zero Entrust</strong> de la <a href="https://nlnet.nl">fondation NLNet</a> pour financer le support de travaux dans Canaille :</p>
<ul>
<li><a href="https://gitlab.com/yaal/Canaille/-/merge_requests/149">la généricisation de la connexion aux bases de données</a>. Ce furent des travaux préparatoires au branchement de bases de données différentes de LDAP ;</li>
<li><a href="https://gitlab.com/yaal/Canaille/-/merge_requests/158">la connexion à des bases de données SQL</a>, qui permet à Canaille de s’interfacer avec un bon nombre de systèmes de bases de données répandus ;</li>
<li><a href="https://pytest-iam.readthedocs.io">pytest-iam</a>, un outil qui permet de préparer et lancer une instance de Canaille, afin d'être utilisée dans des suites de tests unitaires avec <a href="http://pytest.org">pytest</a>.</li>
</ul>
<p><a href="https://nlnet.nl"><img alt="Canaille" src="https://yaal.coop/media/img/logo_nlnet.svg"/></a></p>
<p>Ces développements ont été achevés fin novembre 2023, et ont été la source de nombreux réusinages, de nombreuses corrections de bogues, et plus généralement d’une meilleure conception et d’une meilleure fiabilité de Canaille.
Nous sommes particulièrement reconnaissant·es à la fondation NLNet de nous avoir permis de travailler sur notre outil, et de nous aider à contribuer à notre échelle à l’écosystème du logiciel libre.</p>
<h2>Et la suite ?</h2>
<h3>Passer en version bêta</h3>
<p>Nous avons depuis le début gardé Canaille en version <em>alpha</em>, nous sommes à l’heure actuelle à la version <code>0.0.35</code>.
Nous indiquions que le logiciel était impropre aux environnements de production.
C’était pour nous un moyen de pouvoir expérimenter dans notre coin sans avoir à se soucier de rétrocompatibilité.
Nous souhaitons sévir une dernière fois en <a href="https://gitlab.com/yaal/Canaille/-/issues/138">remettant à plat la manière de configurer Canaille</a> avant de passer Canaille en <em>bêta</em>, et lever les mises en garde d’usage.</p>
<p>Nous regroupons les tickets pour le passage en version bêta de Canaille dans <a href="https://gitlab.com/yaal/canaille/-/milestones/1">ce jalon</a>.</p>
<h3>Passer en version stable</h3>
<p>Les travaux que nous immaginons réaliser pour passer d’une version bêta à une version finale sont principalement des efforts de documentation, d’installation et de prise en main de Canaille.
L’objectif est pour nous de rendre Canaille facile d’accès, afin de créer de l’usage et collecter des retours utilisateurs.</p>
<p>Nous regroupons les tickets pour le passage en version stable de Canaille dans <a href="https://gitlab.com/yaal/canaille/-/milestones/2">ce jalon</a>.</p>
<h3>Et au-delà…</h3>
<p>Pour l’avenir nous souhaitons travailler sur le <a href="https://fr.wikipedia.org/wiki/Provisionnement">provisionnement</a>, en implémentant la norme <a href="https://www.rfc-editor.org/rfc/rfc7642.html">SCIM</a>.
Ce travail permettra de découpler l’authentification des utilisateur·ices et la création des comptes utilisateur·ices.
En effet aujourd’hui dans les outils externes que nous avons branchés à Canaille, les comptes des utilisateur·ices sont créés à la première connexion.
Cela peut s’avérer problématique dans certaines situations : par exemple si l’on veut partager des fichiers dans Nextcloud avec un utilisateur·ice qui ne s’est encore jamais connecté.
SCIM permet aussi de supprimer des comptes utilisateur·ices sur ces outils externes, tâche qui doit être réalisée plus ou moins manuellement à l’heure actuelle.</p>
<p>Parmi les chantiers à venir, nous voyons aussi <a href="https://gitlab.com/yaal/Canaille/-/issues/155">le travail sur la déconnexion unique</a>, ou <em>Single Log-Out (<abbr>SLO</abbr>)</em>.
C’est un développement qui devra être réalisé en premier lieu dans authlib, et qui permettra aux utilisateur·ices de se déconnecter de tous les outils en une seule action.
C’est une fonctionnalité qui apportera de la sécurité et du confort d’utilisation.</p>
<p>Enfin, nous aimerions travailler sur une gestion avancée des groupes d’utilisateur·ices et des droits, ainsi que sur des mécanismes d’<a href="https://fr.wikipedia.org/wiki/Double_authentification">authentification multi-facteurs</a>.</p>
<p>Si tout cela vous intéresse, vous pouvez tester Canaille immédiatement sur <a href="https://canaille.yaal.coop">notre interface de demo</a>. Canaille est évidemment ouvert aux contributions, alors si vous souhaitez nous aider dans tout ça, <a href="https://gitlab.com/yaal/canaille">la porte est ouverte</a> !</p><ol class="simple-footnotes"><li id="sf-canaille-nlnet-pytest-iam-1">enfin, un logiciel qui <em>implémente</em> LDAP, ici je parle indifféremment du protocole ou de ses implémentations <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-1-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-2">du moins avec OpenLDAP <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-2-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-3">ce que nous avons fait, notre numéro à l’IANA est le <a href="https://www.iana.org/assignments/enterprise-numbers/?q=yaal">56207</a> <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-3-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-4">d’accord, la comparaison est fallacieuse puisque ces différentes bases de données ne répondent pas aux mêmes besoins, mais l’ordre de grandeur est révélateur de l’intérêt autour de ces technologies <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-4-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-5">le supermarché coopératif de l’agglomération bordelaise <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-5-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-6">par abus de langage, je dirai simplement <em>OIDC</em> <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-6-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-7">l’« Internet Engineering Task Force » un organsime étasunien de développement et de promulgation de standards <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-7-back">↩︎</a></li><li id="sf-canaille-nlnet-pytest-iam-8">Ils peuvent aussi êtres moteurs de nouvelles améliorations, comme <a href="https://www.rfc-editor.org/rfc/rfc7628.html">RFC7628</a> ou <a href="https://www.rfc-editor.org/rfc/rfc9068.html">RFC9068</a> qui furent des usages avant d’être des standards. <a class="simple-footnote-back" href="https://yaal.coop/blog/feeds/all.atom.xml#sf-canaille-nlnet-pytest-iam-8-back">↩︎</a></li></ol>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Canaille, a lightweight identity and authorization management software</title>
        <link href="https://yaal.coop/blog/en/canaille-nlnet-pytest-iam" />
        <id>https://yaal.coop/blog/en/canaille-nlnet-pytest-iam</id>
        <updated>2023-11-28T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Since a while, the Yaal Coop team is working on Canaille, an identity and authorization management software <em>(or <abbr>IAM</abbr>)</em>.
At the occasion of the end of an endeavour that benefited the help of the NLNet foundation, we want to tell the history around Canaille.</p>
<p><a href="https://canaille.yaal.coop"><img alt="Canaille" src="https://yaal.coop/media/img/canaille.webp"/></a></p>
<h2>At first was the Single Sign On</h2>
<p>At Yaal Coop (like anywhere else) we use a bunch of tools to work together as a team.
Emails, files, address book, project management, time tracking, accountability, continuous integration, bug reporting… and the list goes on.
For the comfort of use (and for security), those tools are generally plugged to a central software that manages user accounts and accesses.
Usually, LDAP[ref]or more exactly, a software implementing the LDAP protocol[/ref] is used for that, and this is called a directory.
If a service is connected to a directory, you do not need to register to that service, you can just use your usual password, the one you set in the directory.
It is convenient for you since you just have one single password to remember <em>(or to forget)</em>. This is what is called <em>Single Sign On (<abbr>SSO</abbr>)</em>.
It is also convenient for people managing the user accounts in your organization, as they can create and revoke accounts for all the plugged services at a time.</p>
<p>LDAP is old and robust, and for software those are qualities.
The few decades of experience behind LDAP make it a battle-tested technology compatible with a large selection of services.
But unfortunately LDAP is also complicated and abstruse.</p>
<p>Its <em>tree</em> model looks like few other things you might know, the documentation is rare and obscure, conventions are intriguing, with a lot of distressing acronyms, tooling is sparse…
Also, this was made for data often read but rarely written.
The data models LDAP offers cannot easily evolve.
Generally, the provided ones allow to handle basic attributes on users and groups.
If you want to manage more advanced aspects like the favourite color of users, then you need to write your own data models[ref]that are called <em>schemas</em>[/ref].
And you'd better be confident when you do it, because no update mechanism is provided for neither data nor data models[ref]at least with OpenLDAP[/ref].
Then, if you wish to share your data models with the world, it is advised that your register at the <a href="https://iana.org">IANA</a>[ref]what we did, our IANA number is <a href="https://www.iana.org/assignments/enterprise-numbers/?q=yaal">56207</a>[/ref], and provide an online reference of your schemas.</p>
<p>When we took a close look at the LDAP universe, we had the impression that once set up, LDAP installation were left alone for years ;
like if people who might had knowledge to share had flew the austerity of that technology without documenting their adventures, and without need to returning to it because it <em>just works</em>.
I am barely exaggerating, if we have a look[ref]OK, the comparison has limits since those different databases are not used for the same needs, but the magnitude of the numbers says something about the interest around those technologies[/ref] at the number of questions in <a href="https://stackoverflow.com">stackoverflow</a>, <a href="https://stackoverflow.com/questions/tagged/ldap">ldap</a> has approximately 1000 questions, while <a href="https://stackoverflow.com/questions/tagged/postgresql">postgresql</a> or <a href="https://stackoverflow.com/questions/tagged/mongodb">mongodb</a> have around 14.000, and <a href="https://stackoverflow.com/questions/tagged/mysql">mysql</a> has 45.000.</p>
<h2>Then came the Single Log In</h2>
<p>During our volunteer time at <a href="https://supercoop.fr">Supercoop</a>[ref]a cooperative supermarket near Bordeaux, France[/ref], among other tasks, we worked to install collaboration software, like we did for ourselves.
Obviously, those tools were plugged on a LDAP directory.
We noticed that the <em>members management</em> team of the supermarket was spending a certain amount of time dealing with user support, notably with password reset demands.
People were failing to use the tools we deployed for them as soon as the first login step.
This verdict pushed us to look for <em>Single Login Identification (<abbr>SLI</abbr>)</em> software (free and open-source, obviously), in replacement or in addition to our historical directory.
What SLI brings, is that users can navigate between services without having to sign in every time.
They can switch from the webmail interface to the calendar without having to make a step by the authentication screen, while with a simple directory, they would have to enter their password once for each service.
For a non tech-savvy public, this is the opportinity to get rid of several technical screens, limit the error sources and the frustration.</p>
<p>Currently the predilection protocols for SLI are OAuth2 and OpenID Connect <em>(<abbr>OIDC</abbr>)</em>[ref]for sake of simplicity, I will keep to <em>OIDC</em>[/ref].
(There are other existing standards, more historical or more focused towards big organizations, like <a href="https://fr.wikipedia.org/wiki/Security_assertion_markup_language">SAML</a> or <a href="https://fr.wikipedia.org/wiki/Central_Authentication_Service">CAS</a>.)
The OAuth2 and OIDC specifications are <em>recent</em> but they still benefit from a decade of feedback.
Tooling and documentation are numerous, the community is alive and active, and standards are still evolving at this day with the work of the <abbr>IETF</abbr> <a href="https://datatracker.ietf.org/wg/oauth/about/"><em>oauth</em> workgroup</a>.
But here again, everything is not perfect and OIDC comes with its difficulties.
First of all, OAuth2 and OIDC make about <a href="https://canaille.readthedocs.io/en/latest/specifications.html#state-of-the-specs-in-Canaille">30 different standards</a>, some of which contradicting or bringing corrections upon prior standards.
All of those are not pertinent for what we want to do, but simply understanding how work the few standards that actually interests us already requires a certain amount of time and work.
The OIDC implementations – by the IAMs or the services connected to IAMs – are sometimes partial or bugged.
To make nothing better, big industry actors sometimes deliberately take some liberties with the standards, and make some additional developments a requirements to be compatible with their software.[ref]They can also be a driving force for new features, like <a href="https://www.rfc-editor.org/rfc/rfc7628.html">RFC7628</a> or <a href="https://www.rfc-editor.org/rfc/rfc9068.html">RFC9068</a> that were commonly used before they became standards.[/ref]</p>
<p>Let's get back on topic. For Supercoop, we wanted to find a tool that would be utterly simple from several point of views:</p>
<ul>
<li>for the final users: the volunteers of the shop.
  They must be able to use the tool without any prior technical knowledge, and without help;</li>
<li>for the <em>members management team</em>.
  We wanted a relatively simple tool where a little bit of learning would be acceptable but not desirable.
  As the cooperative supermarket operates with benevolent labour, we want to take care of the volunteer time and avoid disagreeable tasks.</li>
<li>for the <em>IT team</em>.
  Here again simplicity is at stake.
  If there is a too steep learning curve on the tools the supermarket uses, there will be an issue for recruiting competent people to help us.
  The nature of the benevolent participation of the shop make that volunteers are helping punctually, and rarely engage for years, so they do not always have the time to learn the whole technical stack.
  Ideally the IT team should be able to administrate the tool we are seeking with a superficial knowledge of the underlying protocols.
  <em>And with the descriptions I made of LDAP and OIDC, you start to make an idea of the problem we have</em>.</li>
</ul>
<p><a href="https://canaille.readthedocs.io/en/latest/specifications.html#comparison-with-other-providers">Our search</a> showed us that there was a dozen of tools that could answer our needs.
However, none was fitting all our expectations.
Actually, by their very nature, the IAM software are intended to big organizations, that consequently can afford to hire competent people to administrate them, so complexity is not really an issue.
Those are mostly big powerful software, with a large protocol compatibility not pertinent for us, and requiring some technical knowledge for installation, maintenance and administration.
Pushed by our curiosity, we finally hacked something on our side.</p>
<h2>Canaille</h2>
<p>A few times later, our prototype had grown bigger and became <a href="https://canaille.yaal.coop">Canaille</a>.</p>
<h3>The features</h3>
<p>Canaille is a user and group management software that allows account creation, edition, administration, registration, forgotten password reset, user invitation etc.
In addition, Canaille implements OIDC and provide a SLI layer for other services. Its interface is customizable and… that's all.
We try to keep the functional scope tight so Canaille can stay simple to maintain and to operate.</p>
<p>Canaille can be used for:</p>
<ul>
<li>bringing an account edition interface on top of a LDAP directory.
  The tooling around LDAP being quite sparse, Canaille can be a convenient option and allow utilities like password reset.</li>
<li>bringing a SLI layer on top of a LDAP directory.
  If your organization has a historical LDAP directory and you want to modernize your stack with SLI, Canaille can discretely integrate your existing stack (almost) without modifying anything, and let you the time to prepare (or not) a migration.</li>
<li>develop applications relying upon an OIDC server.
  If, like us, you are doing software development and regularly work on applications that needs to connect to a OIDC server, then you can use Canaille in your development environment.
  Canaille being very light, this is now our tool of choice to work on client applications.</li>
<li>test applications relying upon an OIDC server.
  We also use canaille in unit tests suites, with <a href="https://pytest-iam.readthedocs.io/en/latest/">pytest-iam</a>.
  This is a pytest plugin that configures and run a Canaille instance so your unit tests suite can achieve actual OIDC connections.</li>
</ul>
<h3>The technical choices</h3>
<p>Canaille is written in Python, with <a href="https://flask.palletsprojects.com/en/3.0.x/">Flask</a> for the backend and <a href="https://fomantic-ui.com/">fomantic-ui</a> and <a href="https://htmx.org">htmx</a> for the frontend.
We like the simplicity of Python and Flask, and strongly believe those are arguments that make contributions easier and increase software longevity.
We have been shocked by our discovery of HTMX earlier this year, that in short allows us to build dynamical pages without writing Javascript.
One language less is as much less complexity in the project.</p>
<p>Under the hood, Canaille can be plugged to a LDAP directory or a SQL database.</p>
<h3>The development techniques</h3>
<p>We use Canaille in production, at Supercoop where it is used to manage 1800 users, but also in our own stack in our <a href="https://nubla.fr">Nubla</a> mutualized cloud services, and on dedicated Nubla Pro instances.
That large userbase allows us to collect user feedback, and we improve Canaille gradually in reaction to demands and according to our roadmap.</p>
<p>Cannaille development follows the principles of the <em>Test Driven Development (TDD)</em> when possible.
The <a href="https://en.wikipedia.org/wiki/Code_coverage">code coverage</a> reaches 100% <em>(including branches)</em>, and this is a prerequisite for new contributions.
In addition to giving us confidence in our tests, this allowed us to simply delete unused pieces of code.
Bugs are easier to find when there is less code to search them into.</p>
<p>Canaille uses all the modern Python source code linters and formatters, with <a href="https://gitlab.com/yaal/Canaille/-/blob/main/.pre-commit-config.yaml">pre-commit</a>, and the unit tests are run on all the officially supported Python versions.</p>
<p>Finally, the translation of Canaille is done by the community with <a href="https://hosted.weblate.org/engage/Canaille/?utm_source=widget">Weblate</a>.</p>
<h3>Contributions</h3>
<p>Like most of modern software, Canaille relies on libraries so we don't have to re-invent what is already existing.</p>
<p>At Yaal Coop for all our projects, when we find bugs in libraries, we follow a strategy that consists in implementing fixes both in our code and the libraries at the same time.
At first we patch our code with temporary but functional fixes.
However all that code we write is a maintenance burden to come, so in parallel we discuss with the maintainers of those libraries, and propose better conceived long term fixes.
This is for us a guarantee of the sustainability of those pieces of software we rely upon, and this is a way to contribute to that necessary FLOSS ecosystem.
Once the upstream library is patched, we delete our quick fix.</p>
<p>In the same fashion when we wish additional features in libraries, we discuss our motivations with maintainers and sometimes provide implementations.
We have for instance developed the OIDC specifications <a href="https://github.com/lepture/authlib/pull/505">RFC7591</a> and <a href="https://github.com/lepture/authlib/pull/586">RFC9068</a> in <a href="https://github.com/lepture">authlib</a>, a library Canaille uses to deal with OIDC.</p>
<p>The results of those efforts can be seen in our <a href="https://yaal.coop/blog/en/tag/contributions">seasonal blogposts</a> about our FLOSS contributions.</p>
<p>The chance of the contributions brought us to share the maintenance of certain libraries we rely upon, like <a href="https://github.com/wtforms/wtforms">wtforms</a> that is a form management tool, or <a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a> and the underlying <a href="https://github.com/jumbojett/OpenID-Connect-PHP">OpenIDConnect-PHP</a> that allow <a href="https://nextcloud.com">nextcloud</a> (the file manager integrated in Nubla) to connect with Canaille.</p>
<p>We also modestly sponsor the maintainers of <a href="https://github.com/lubber-de">fomantic-ui</a> and <a href="https://github.com/lepture">authlib</a> on a monthly basis.</p>
<h2>The help of the NLNet foundation</h2>
<p>Canaille has been developed to answer specific needs we met: initially Canaille was only made to work with LDAP directories.
Watching the ecosystem, we noticed that more and more software became compatible with OIDC in addition to LDAP.
Ultimately, if no service we use directly rely upon LDAP, then we could consider a replacement database with which we feel more comfortable.
In addition to this, it is more likely that people interested by the Canaille approach will have experience with things like SQL than with LDAP.
To go towards this directory, we sollicitated the <strong>NGI Zero Entrust</strong> fund of the <a href="https://nlnet.nl">NLNet foundation</a> in the late 2022, for a amount of 7.000€, to help us realize tasks on Canaille (and around):</p>
<ul>
<li><a href="https://gitlab.com/yaal/Canaille/-/merge_requests/149">database connection genericity</a>.
  This was a mandatory preparatory step to plugging additional databases than LDAP;</li>
<li><a href="https://gitlab.com/yaal/Canaille/-/merge_requests/158">SQL databases support</a>.
  This allows Canaille to connect to a lot of widespread databases like postgresql, mariadb and sqlite, thanks to <a href="https://www.sqlalchemy.org">sqlalchemy</a>.</li>
<li><a href="https://pytest-iam.readthedocs.io">pytest-iam</a>.
  This is a tool that can prepare and run a Canaille instance in the purpose of unit testing Python applications with <a href="http://pytest.org">pytest</a>.</li>
</ul>
<p><a href="https://nlnet.nl"><img alt="Canaille" src="https://yaal.coop/media/img/logo_nlnet.svg"/></a></p>
<p>Those developments have been achieved in november 2023, and have implied numerous refactoring, bugfixes, and better conception and reliability on Canaille.
We are very grateful towards the NLNet foundation for having allowed us to work on our tool, and help at our scale to contribute to the free and open source ecosystem.</p>
<h2>What's next?</h2>
<h3>Go in beta version</h3>
<p>From the beginning we have kept Canaille in <em>alpha</em>, we are currently at version <code>0.0.35</code>.
We advise in the documentation that the software is still not suited for production environments.
This was for us a way to experiment and break things without having to be worried about compatibility.
We would like to break one last little thing by <a href="https://gitlab.com/yaal/Canaille/-/issues/138">re-thinking the configuration files</a> before we let Canaille go in <em>bêta</em>, and remove usage warnings.</p>
<p>We track the beta version tasks in <a href="https://gitlab.com/yaal/canaille/-/milestones/1">this milestone</a>.</p>
<h3>Go in stable version</h3>
<p>The work we intend to realize to go from a bêta version to a finale version will essentially consists in documentation efforts and ease of installation and usage of Canaille.
The goal is to make Canaille really easy to access, in order to create usage and collect more user feedback.</p>
<p>We track the finale version tasks in <a href="https://gitlab.com/yaal/canaille/-/milestones/2">this milestone</a>.</p>
<h3>And beyond…</h3>
<p>In the future, we would like to work on <a href="https://en.wikipedia.org/wiki/Provisioning_(technology)#User_provisioning">provisioning</a>, by implementing the <a href="https://www.rfc-editor.org/rfc/rfc7642.html">SCIM</a> specification.
This will allow to decouple user authentication and account creation.
Indeed, at the moment user accounts are created the first time users log in at our services.
This can raise issues in some situations: for instance one cannot share files in Nextcloud with users who have not log in yet.
SCIM also provides a mechanism to delete user accounts in those services, that is a thing we do more or less manually at the moment.</p>
<p>Among the things we look forward to implement, there are also the <em><a href="https://gitlab.com/yaal/Canaille/-/issues/155">Single Log-Out</a> (<abbr>SLO</abbr>)</em> OIDC specifications.
This will allow users to disconnect from all the services in a single action.
SLO is a feature that will bring security and comfort of use.
This will need to be developed in authlib in a first time.</p>
<p>At last, we would like to work on advanced group management and permissions, and on <a href="https://en.wikipedia.org/wiki/Multi-factor_authentication">multi-factor authentication</a> to bring even more flexibility and security in Canaille.</p>
<p>Canaille is open to contributions, if you want to help us in this endeavour, <a href="https://gitlab.com/yaal/canaille">the door is open</a>!</p>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Les nouveautés de Python 3.12</title>
        <link href="https://www.docstring.fr/blog/les-nouveautes-de-python312/" />
        <id>https://www.docstring.fr/blog/les-nouveautes-de-python312/</id>
        <updated>2023-10-23T11:06:09Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Dans cet article, nous allons passer en revue toutes les nouveautés de la version 3.12 de Python.</p>
<a href="https://news.humancoders.com/t/python/items/20772-les-nouveautes-de-python-3-12"><img src="https://www.docstring.fr/static/img/illustrations/radio-907x907.webp"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20772-les-nouveautes-de-python-3-12#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20772-les-nouveautes-de-python-3-12">Les nouveautés de Python 3.12</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Thibault Houdon</name>
        </author>
    </entry>
    <entry>
        <title>Améliorer son code Django</title>
        <link href="https://klemenstrajhar.substack.com/p/how-to-write-better-django-code" />
        <id>https://klemenstrajhar.substack.com/p/how-to-write-better-django-code</id>
        <updated>2023-10-12T03:32:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Pour les Pythonistes : un article qui donne des bonnes pratiques pour écrire du clean code avec Django. Réduire le couplage, granularité des tests, utilisation des modèles et des vues, etc.</p>
<a href="https://news.humancoders.com/t/python/items/20755-ameliorer-son-code-django"><img src="https://substackcdn.com/image/fetch/w_1200,h_600,c_fill,f_jpg,q_auto:good,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee576f2c-a467-4a6e-8061-8d51894f01bf_1200x546.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20755-ameliorer-son-code-django#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20755-ameliorer-son-code-django">Améliorer son code Django</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Vincent Daubry</name>
        </author>
    </entry>
    <entry>
        <title>Summer 2023 FOSS contributions by the Yaal Coop team</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2023" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2023</id>
        <updated>2023-09-22T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>This summer we decided to sponsor two authors of tools we are depending on. This is a small amount for the moment, but hopefully this will grow or we add more recipients to the list.</p>
<p>We spent a bit of energy on Canaille, and implementing the big part of our NLNet subsidy, that is the database backend genericity. The <a href="https://gitlab.com/yaal/canaille/-/merge_requests/149">inmemory backend</a> allowed us to use canaille in <a href="https://pytest-iam.readthedocs.io/en/latest/">pytest-iam</a>, a tool that bring a lightweight OpenID Connect provider to be used in your unit tests.</p>
<h2>Sponsoring</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> for his work on <a href="https://fomantic-ui.com">Fomantic-UI</a>, a nice CSS framework we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI is used on other tools we rely on, like <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> for his work on <a href="https://authlib.org">authlib</a>, a python authentication library we use in <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/136">Multiple form fields support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/137">Pages are boosted with HTMX</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/138">Bump to jquery 3.7.0</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/139">Fix user identification in URLs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/141">Configuration option to disable javascript</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/142"><code>USER_FILTER</code> configuration is parsed with jinja</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/143"><code>OIDC.REQUIRE_NONCE</code> configuration parameter</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/144">Modals are HTML pages instead of JS elements</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/145">Fix Babel requirement</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/146">Phone number validation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/147">Email confirmation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/148">User registration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/149">Alternative inmemory backend</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/150">Installation extra packages</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/151">Merged the core and OIDC login screens</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/152">Bump to fomantic-ui 2.9.3</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/794">Stop python 3.7 support</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/795">Fix style warnings</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/796">Documentation improvements</a></li>
</ul>
<h2><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h2>
<p><em>Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/571">Unit test fixes</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/572">Janitoring</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/574">Stop python 3.7 support</a></li>
</ul>
<h2><a href="https://github.com/spiral-project/ihatemoney">ihatemoney</a></h2>
<p><em>A simple shared budget manager web application</em></p>
<ul>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1158">RSS feeds</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1203">Unit test fixes</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1211">Dynamic year in the documentation</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1213">Pytest migration</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1215">Unit test speed-up</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1216">Janitoring</a></li>
</ul>
<h2><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h2>
<p><em>Controls a slapd process in a pythonic way</em></p>
<ul>
<li><a href="https://github.com/python-ldap/python-slapd/pull/8">LDAP tree initialization utility</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Identity and Access management library for python</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/570">Stop python 3.7 support</a></li>
<li><a href="https://github.com/lepture/authlib/pull/571">tox option to pass arguments to pytest</a></li>
<li><a href="https://github.com/lepture/authlib/pull/572">Django in-memory database usage in unit tests</a></li>
<li><a href="https://github.com/lepture/authlib/pull/574">SQLAlchemy warning fix</a></li>
<li><a href="https://github.com/lepture/authlib/pull/575">Unit test warning fix</a></li>
<li><a href="https://github.com/lepture/authlib/pull/576">Multiple endpoints of a kind can be registered</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/pytest-iam">pytest-iam</a></h2>
<p><em>A lightweight OAuth2/OIDC server to be used in your test suite</em></p>
<ul>
<li><a href="https://pytest-iam.readthedocs.io">First releases and documentation</a></li>
</ul>
<h2>Debian</h2>
<ul>
<li><a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=915583#30">New style proposal</a> for Sphinx documentations, which is currently used for <a href="https://www.debian.org/doc/debian-policy/">debian-policy</a> and could be used in the future for the <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/4">release notes</a></li>
<li><a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927228">Search on the Supervisor bug report</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;été 2023</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2023" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2023</id>
        <updated>2023-09-22T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet été nous avons décidé de sponsoriser deux auteurs d'outils desquels nous dépendons. C'est un petit montant pour le moment, mais nous espérons qu'à l'avenir il augmentera ou que la liste des récipiendaires s'élargira.</p>
<p>Nous avons mis une partie de notre énergie sur Canaille, en implémentant le gros morceau de notre engagement à la subvention NLNet, à savoir la généricité des backends de base de données. L'implémentation de la <a href="https://gitlab.com/yaal/canaille/-/merge_requests/149">base de données en mémoire</a> nous a permis d'utiliser Canaille dans <a href="https://pytest-iam.readthedocs.io/en/latest/">pytest-iam</a>, un outil qui permet de lancer un serveur OpenID Connect dans des tests unitaires.</p>
<h2>Mécénat</h2>
<ul>
<li><a href="https://github.com/sponsors/lubber-de">Marco 'Lubber' Wienkoop</a> pour son travail sur <a href="https://fomantic-ui.com">Fomantic-UI</a>, un chouette framework CSS que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>. Fomantic-UI est aussi utilisé par d'autres outils sur lesquels nous comptons, comme <a href="https://forgejo.org">Forgejo</a>.</li>
<li><a href="https://github.com/sponsors/lepture">Hsiaoming Yang</a> pour son travail sur <a href="https://authlib.org">authlib</a>, une bibliothèque python d'authentification que nous utilisons dans <a href="https://gitlab.com/yaal/canaille">canaille</a>.</li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/136">Support des champs de formulaire multiples</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/137">Les pages web sont boostées avec HTMX</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/138">jquery 3.7.0</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/139">Correction des identifiants utilisateur dans les URL</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/141">Ajout d'une option de configuration pour désactiver javascript</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/142">Le paramètre <code>USER_FILTER</code> est analysé avec jinja</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/143">Ajout d'un paramètre <code>OIDC.REQUIRE_NONCE</code></a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/144">Les fenêtres modales sont en HTML plutôt qu'en JS</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/145">Correction sur la dépedance à Babel</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/146">Validation des numéros de téléphone</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/147">Confirmation des adresses email</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/148">Page d'inscription</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/149">Implémentation d'un backend en mémoire</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/150">Configuration de packages <code>extras</code> pour des installations dans différents contextes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/151">L'écran de connexion principal et OIDC sont fusionnés</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/152">fomantic-ui 2.9.3</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/794">Arrêt du support de python 3.7</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/795">Correction d'avertissements de style</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/796">Améliorations sur la documentation</a></li>
</ul>
<h2><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h2>
<p><em>Intégration de WTForms dans Flask</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/571">Corrections sur les tests unitaires</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/572">Conciergerie</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/574">Arrêt du support de python 3.7</a></li>
</ul>
<h2><a href="https://github.com/spiral-project/ihatemoney">ihatemoney</a></h2>
<p><em>Une application web simple de gestion de budget</em></p>
<ul>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1158">Flux RSS</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1203">Corrections sur les tests unitaires</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1211">Année dynamique dans la documentation</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1213">Migration à pytest</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1215">Amélioration de la vitesse d'exécution des tests unitaires</a></li>
<li><a href="https://github.com/spiral-project/ihatemoney/pull/1216">Conciergerie</a></li>
</ul>
<h2><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h2>
<p><em>Interface pythonique pour contrôler un serveur OpenLDAP</em></p>
<ul>
<li><a href="https://github.com/python-ldap/python-slapd/pull/8">Utilitaire d'initialisation de l'arbre LDAP</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Bibliothèque python de gestion des identités et des accès</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/570">Arrêt du support de python 3.7</a></li>
<li><a href="https://github.com/lepture/authlib/pull/571">Passage d'options de tox à pytest</a></li>
<li><a href="https://github.com/lepture/authlib/pull/572">Utilisation d'une base de données Django en mémoire dans les tests unitaires</a></li>
<li><a href="https://github.com/lepture/authlib/pull/574">Corrections d'avertissements de SQLAlchemy</a></li>
<li><a href="https://github.com/lepture/authlib/pull/575">Corrections d'avertissements dans les tests unitaires</a></li>
<li><a href="https://github.com/lepture/authlib/pull/576">Différents points d'accès de même type peuvent être enregistrés</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/pytest-iam">pytest-iam</a></h2>
<p><em>Serveur OAuth2/OIDC léger pour vos tests unitaires</em></p>
<ul>
<li><a href="https://pytest-iam.readthedocs.io">Premières publications et documentation</a></li>
</ul>
<h2>Debian</h2>
<ul>
<li><a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=915583#30">Nouvelle proposition de style</a> pour les documentation Sphinx, qui est utilisé actuellement pour <a href="https://www.debian.org/doc/debian-policy/">debian-policy</a> et potentiellement demain pour les <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/4">notes de publication</a></li>
<li><a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927228">Enquête sur un rapport de bogue concernant Supervisor</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Python : f-string vs str()</title>
        <link href="https://www.olivierpons.fr/2023/09/05/python/" />
        <id>https://www.olivierpons.fr/2023/09/05/python/</id>
        <updated>2023-09-05T15:46:44Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Quelle est la différence de performance entre <code style="font-size: 70%;">f"{x}"</code> et <code style="font-size: 70%;">str(x)</code> ?</h1>
<p>Voici mes tests qui m’ont surpris, car je m’attendais à l’inverse :</p>
<p><code>from typing import Dict</code></p>
<p>def benchmark() -&gt; None:<br/>
  """Main<br/>
  function for benchmark.<br/>
  """<br/>
  t1 = timeit.timeit("f_str()",<br/>
                     globals=globals(),<br/>
                     number=50000000)<br/>
  t2 = timeit.timeit("u_str()",<br/>
                     globals=globals(),<br/>
                     number=50000000)<br/>
  t3 = timeit.timeit("n_str()",<br/>
                     globals=globals(),<br/>
                     number=50000000)<br/>
  d: Dict[str, float] = {<br/>
    "f-string": t1,<br/>
    "str": t2,<br/>
    "no str": t3<br/>
  }<br/>
  s: Dict[str, float] = {k: v<br/>
                         for k, v<br/>
                         in sorted(d.items(),<br/>
                                   key=lambda i:<br/>
                                   i[1])}<br/>
  f: float = min(s.values())<br/>
  print("Method\tTime\tPerc.")<br/>
  print("------\t----\t-----")<br/>
  for k, v in s.items():<br/>
    p: float = (v / f) * 100<br/>
    print(f"{k}\t{v:.2f}\t{p:.2f}%")</p>
<p>if __name__ == "__main__":<br/>
  import timeit<br/>
  class T:<br/>
    def __init__(<br/>
            self, l: str) -&gt; None:<br/>
      self.l: str = l<br/>
  o: T = T("test")<br/>
  def f_str() -&gt; str:<br/>
    return f"{o.l}"<br/>
  def u_str() -&gt; str:<br/>
    return str(o.l)<br/>
  def n_str() -&gt; str:<br/>
    return o.l<br/>
  benchmark()</p>
<h1>Explications</h1>
<ul>
<li><code>f"{self.label}"</code> utilise le mécanisme d’interpolation de chaînes de caractères de Python qui peut être légèrement plus rapide parce qu’il est optimisé pour concaténer des littéraux de chaîne et des variables ;</li>
<li><code>str(self.label)</code> appelle explicitement le constructeur de la classe str, ce est un peu plus lent en raison de l’appel de fonction.</li>
</ul>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Python sans GIL !</title>
        <link href="https://www.bitecode.dev/p/whats-up-python-the-gil-removed-a" />
        <id>https://www.bitecode.dev/p/whats-up-python-the-gil-removed-a</id>
        <updated>2023-08-03T20:40:49Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Grosse annonce pour les Pythonistes : la proposition de retirer le GIL (Global Interpreter Lock) a été acceptée, permettant le multi-threading natif en Python, une version expérimentale va bientôt être publiée</p>
<a href="https://news.humancoders.com/t/python/items/20623-python-sans-gil"><img src="https://substackcdn.com/image/fetch/w_1200,h_600,c_fill,f_jpg,q_auto:good,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F151d23d3-4594-43d1-b1bb-ca2d72ae02aa_966x966.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20623-python-sans-gil#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20623-python-sans-gil">Python sans GIL !</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Vincent Daubry</name>
        </author>
    </entry>
    <entry>
        <title>FOSS contributions from the Yaal Coop team during spring 2023</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-printemps-2023" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-printemps-2023</id>
        <updated>2023-06-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2><a href="https://addons.mozilla.org/fr/firefox/addon/html-rfc/">htmlRFC</a></h2>
<p><em>Firefox plug-in displaying a link for RFCs in plain text format to HTML one</em></p>
<ul>
<li>Accept RFCs on <a href="https://rfc-editor.org">rfc-editor.org</a> website: <a href="https://gitlab.com/sblondon/htmlrfc/-/commit/2db775f4193b9eb5d645e67b28cb01fdb79e3d8f">plugin enabled on rfc-editor.org site</a> and <a href="https://gitlab.com/sblondon/htmlrfc/-/commit/dff78979003de97bddc7b41dd0cdfa5c7f4cea39">redirect to rfc-editor</a></li>
<li>Release v.1.2</li>
</ul>
<h2>Debian</h2>
<ul>
<li>Improve <a href="https://salsa.debian.org/games-team/blastem/-/merge_requests/2">BlastEm</a> manpage</li>
<li>During release notes migration from DocBook to Sphinx: <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/2">highlight command line and configuration examples</a>, <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/3">hide 'Created using Sphinx' text</a> in the footer, <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/4">add CSS file to fit Debian style</a></li>
</ul>
<h2>Logrotate</h2>
<p><em>Unix tool for administration of log files on a system which generates a lot of log files</em></p>
<ul>
<li><a href="https://github.com/logrotate/logrotate/pull/508">Turn exit code to 0</a> when the raised error stops the execution. It fits expected behavior for Unix tools.</li>
<li>Minor <a href="https://github.com/logrotate/logrotate/pull/509">documentation</a> improvement.</li>
</ul>
<h2><a href="https://github.com/bebleo/smtpdfix">smtpdfix</a></h2>
<p><em>A SMTP server for use as a pytest fixture that implements encryption and authentication.</em></p>
<ul>
<li><a href="https://github.com/bebleo/smtpdfix/pull/306">Use a random port instead of 8025 by default</a></li>
</ul>
<h2><a href="https://github.com/TkTech/flask-themer">flask-themer</a></h2>
<p><em>Simple theming support for Flask apps.</em></p>
<ul>
<li><a href="https://github.com/TkTech/flask-themer/pull/4">Extend a template from another theme</a></li>
</ul>
<h2><a href="https://github.com/Pylons/zodburi/">zodburi</a></h2>
<p><em>Construct ZODB storage instances from URIs.</em></p>
<ul>
<li><a href="https://github.com/Pylons/zodburi/pull/32">Remove support for ZODB4 and python&lt;3.7</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/118">Account expiration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/119">CSRF protection on every forms</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/120">Dynamic form validation with HTMX</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/121">Dark theme improvements</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/123">SCIM naming convention</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/124">Bump to htmx 1.9.0</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/125">Empty field validation fix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/126">Generic ACL filters</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/127">Bump to htmx 1.9.2</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/128">Password initialization mail recipient bugfix</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/129">Display password recovery button on OIDC login page</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/130">Dates are saved in UTC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/131">Stop support for python 3.7</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/132">Generic backend unit tests</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/134">File-path configuration entries</a></li>
</ul>
<h2><a href="https://anymail.dev/">django-anymail</a></h2>
<p><em>Django email integration for transactional ESPs</em></p>
<ul>
<li><a href="https://github.com/anymail/django-anymail/pull/321">Update domain used by the API, unit tests and documentation</a> due to Sendinblue rebranding to Brevo</li>
</ul>
<h2><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h2>
<p><em>Simple Autocomplete / typeahead component for Svelte</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/197">Call custom ordering functions when opening the menu with an empty input</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant le printemps 2023</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-printemps-2023" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-printemps-2023</id>
        <updated>2023-06-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2><a href="https://addons.mozilla.org/fr/firefox/addon/html-rfc/">htmlRFC</a></h2>
<p><em>Greffon Firefox affichant un lien des RFC au format texte brut vers une version au format HTML</em></p>
<ul>
<li>Acceptation des RFC du site web <a href="https://rfc-editor.org">rfc-editor.org</a> : <a href="https://gitlab.com/sblondon/htmlrfc/-/commit/2db775f4193b9eb5d645e67b28cb01fdb79e3d8f">greffon activé sur le site rfc-editor.org</a> et <a href="https://gitlab.com/sblondon/htmlrfc/-/commit/dff78979003de97bddc7b41dd0cdfa5c7f4cea39">redirection vers rfc-editor</a></li>
<li>Publication d'une version 1.2</li>
</ul>
<h2>Debian</h2>
<ul>
<li>Amélioration de la page de manuel de <a href="https://salsa.debian.org/games-team/blastem/-/merge_requests/2">BlastEm</a></li>
<li>Pour la migration des notes de publication de DocBook à Sphinx : <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/2">coloration syntaxique des commandes et exemples de configuration</a>, <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/3">disparition du texte 'Created using Sphinx'</a> dans le pied-de-page, <a href="https://salsa.debian.org/holgerw/release-notes/-/merge_requests/4">ajout d'un fichier CSS to correspondre au style de Debian</a></li>
</ul>
<h2>Logrotate</h2>
<p><em>Outil Unix pour administrer les journaux sur un système produisant de nombreux journaux</em></p>
<ul>
<li><a href="https://github.com/logrotate/logrotate/pull/508">Passage du code de sortie à 0</a> quand l'erreur provoque l'arrêt de l'exécution du programme. Cela correspond au comportement attendu d'un utilitaire Unix.</li>
<li>Amélioration mineure de la <a href="https://github.com/logrotate/logrotate/pull/509">documentation</a>.</li>
</ul>
<h2><a href="https://github.com/bebleo/smtpdfix">smtpdfix</a></h2>
<p><em>Un serveur SMTP pour pytest avec encryption et authentification.</em></p>
<ul>
<li><a href="https://github.com/bebleo/smtpdfix/pull/306">Utilisation d'un port aléatoire par défaut au lieu de 8025</a></li>
</ul>
<h2><a href="https://github.com/TkTech/flask-themer">flask-themer</a></h2>
<p><em>Support simple de thèmes dans les applications flask</em></p>
<ul>
<li><a href="https://github.com/TkTech/flask-themer/pull/4">Étendre un template depuis un autre thème</a></li>
</ul>
<h2><a href="https://github.com/Pylons/zodburi/">zodburi</a></h2>
<p><em>Construit des storage ZODB à partir d'URIs.</em></p>
<ul>
<li><a href="https://github.com/Pylons/zodburi/pull/32">Arrêt du support de ZODB4 et de python&lt;3.7, ajout de l'intégration continue Github Actions</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/118">Expiration des comptes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/119">Protection CSRF sur tous les formulaires</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/120">Validation dynamique des formulaires avec HTMX</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/121">Améliorations sur le thème sombre</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/123">Conventions de nommage de SCIM</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/124">Mise à jour vers 1.9.0</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/125">Correctif sur la validation de champs vides</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/126">Filtres d'ACL génériques</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/127">Mise à jour vers htmx 1.9.2</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/128">Correctif sur les destinataires des emails d'initalisation de mots de passe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/129">Affichage du bouton de récupération de mot de passe sur la page d'identification OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/130">Les dates sont enregistrées en UTC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/131">Arrêt du support de python 3.7</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/132">Tests unitaires sur les backends génériques</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/134">Les options de configurations peuvent êtres des chemins de fichier</a></li>
</ul>
<h2><a href="https://anymail.dev/">django-anymail</a></h2>
<p><em>Intégration des e-mails dans Django pour les fournisseurs d'e-mails transactionels</em></p>
<ul>
<li><a href="https://github.com/anymail/django-anymail/pull/321">Mise-à-jour du domaine utilisé par l'API, de tests unitaires et de la documentation</a> suite au renommage de Sendinblue en Brevo</li>
</ul>
<h2><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h2>
<p><em>Composant svelte de suggestion d'éléments dans une liste déroulante</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/197">Appel de la fonction personnalisée de tri lors du focus sur le champ</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Ruby Video : Plongez dans l&#39;univers Ruby en vidéos !</title>
        <link href="https://rubyvideo.dev/" />
        <id>https://rubyvideo.dev/</id>
        <updated>2023-06-17T10:42:43Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ruby Video, est un projet inspiré par Python pyvideo.org. L’ambition de Rubyvideo.dev est d’agréger toutes les vidéos liées à Ruby en un seul endroit, avec des capacités de recherche pour faciliter la découverte. Pour cette première version, il y a 707 vidéos de 537 intervenants. Il s’agit uniquement des vidéos de RailsConf de 2012 à 2022.</p>
<p>Rubyvideo.dev est construit avec Rails 7.1 alpha, Hotwire, Litestack et déployé en utilisant MRSK sur un VPS bon marché. 
Ce site utilise aussi l’API de transition de vue : testez-la sur un navigateur Chromium pour profiter de ces transitions de page fluides. Il a été assez facile de la faire fonctionner avec Turbo et Adrien Poly, le créateur, espère que ce repo peut aider à l’adoption de la technologie dans le monde de Rails. Il prévoit d’écrire à ce sujet prochainement.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/20534-ruby-video-plongez-dans-l-univers-ruby-en-videos#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20534-ruby-video-plongez-dans-l-univers-ruby-en-videos">Ruby Video : Plongez dans l'univers Ruby en vidéos !</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Camille Roux</name>
        </author>
    </entry>
    <entry>
        <title>Mojo, superset de Python 35000 fois plus rapide</title>
        <link href="https://youtu.be/pdJQ8iVTwj8" />
        <id>https://youtu.be/pdJQ8iVTwj8</id>
        <updated>2023-06-14T15:21:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Une interview passionnante du créateur de Mojo: un superset de Python orienté IA et ML, jusqu’à 35000 fois plus rapide. Ils discutent C, C++, Python, Swift, hardware, perf, et le futur de la programmation.</p>
<a href="https://news.humancoders.com/t/python/items/20530-mojo-superset-de-python-35000-fois-plus-rapide"><img src="https://i.ytimg.com/vi/pdJQ8iVTwj8/maxresdefault.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20530-mojo-superset-de-python-35000-fois-plus-rapide#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20530-mojo-superset-de-python-35000-fois-plus-rapide">Mojo, superset de Python 35000 fois plus rapide</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Vincent Daubry</name>
        </author>
    </entry>
    <entry>
        <title>Chapitre 2022</title>
        <link href="https://yaal.coop/blog/chapitre-2022" />
        <id>https://yaal.coop/blog/chapitre-2022</id>
        <updated>2023-06-11T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cela commence à faire pas mal de temps qu'on ne vous a pas raconté ce que devenait notre projet coopératif ! En fait on n'a pas vraiment pris le temps d'en discuter publiquement depuis le 24 septembre 2021 dans notre article de blog <a href="https://yaal.coop/blog/de-yaal-a-yaal-coop">De Yaal à Yaal Coop</a> qui raconte la genèse de Yaal Coop 🙈.</p>
<p>Pour remédier à ça, on a décidé de publier ici notre <strong>rapport de gestion 2022</strong>. Le rapport de gestion, rédigé annuellement à l'intention des associé·es avant l'Assemblée Générale Ordinaire (AGO) validant les comptes annuels, permet de faire le point sur la situation de l'entreprise durant l'exercice écoulé et de mettre en perspective celui à venir. On n'est pas encore rompu à l'exercice mais on s'est dit que c'était une bonne idée de le partager avec vous 🙌.</p>
<p>Notre AGO (la deuxième seulement depuis le début de l'aventure !) s'est déroulée mi-mai, en présence de tous nos associés, ou presque (quelle idée aussi d'avoir tenté un vol plané à vélo pendant mes vacances une semaine plus tôt 🤕😗🎶). L'AGO, au-delà de son caractère officiel et obligatoire, est surtout pour nous l'occasion de <strong>faire un pas de côté</strong>, regarder le chemin parcouru et vérifier qu'on ne s'est pas perdu en route. En discuter avec les associé·es non salarié·es qui ne vivent pas notre projet au quotidien est aussi très salutaire ! L'occasion d'échanger sur les bonnes (ou moins bonnes) pratiques, s'inspirer... En buvant quelques bières 🍻 !</p>
<p>Sans plus de transition, voici le rapport que nous leur avons adressé.</p>
<p>N'hésitez pas à <a href="https://yaal.coop/#contact">passer nous voir</a> pour en discuter plus largement si vous le souhaitez ! (Mais toujours pas le mercredi, c'est resté le jour du télétravail collectif 😉)</p>
<hr/>
<p>Cher·e sociétaire,</p>
<p>Nous avons l’honneur de vous présenter notre rapport sur les opérations de l’exercice clos le 31 décembre 2022, ainsi que sur les comptes annuels dudit exercice soumis aujourd’hui à votre approbation. Ce rapport a été rédigé collectivement par le collège des salarié·es de Yaal Coop.</p>
<h2>Un peu d'histoire : les faits marquants de l'année 2022</h2>
<ul>
<li>janvier : Yaal Coop obtient <a href="https://www.entreprises.gouv.fr/fr/entrepreneuriat/aides-et-financement/l-agrement-au-credit-impot-innovation">l'agrément CII</a> : toutes nos prestations liées au développement de prototypes et aux installations pilotes de nouveaux produits sont dorénavant éligibles au CII (Crédit d'Impôt Innovation) pour nos clients. Janvier marque aussi le début d'une mission pour <a href="https://telecoop.fr/">Telecoop</a>, premier opérateur télécom coopératif, d'assistance et développement de nouveaux outils sur quelques jours par mois.</li>
<li>février : Nous démarrons une prestation pour le Ministère de l'Éducation nationale afin de remettre à niveau et poursuivre le développement de leur projet informatique B3Desk (frontal OpenIDConnect de gestion simplifiée des visioconférences BigBlueButton de l'Éducation nationale et des agents de l'État).</li>
<li>mars : Un gros chantier de séparation de l'infrastructure technique de Yaal Coop et Yaal SAS est mené à l'occasion d'une migration de serveurs de notre hébergeur historique Scaleway. On bascule alors notre infrastructure interne sur nos serveurs hébergés chez notre hébergeur associatif local <a href="https://www.aquilenet.fr/">Aquilenet</a> sur lesquels nous gérons un cluster lxc/lxd de conteneurs linux. Yaal SAS devient par la même occasion le premier client officiel de <a href="https://nubla.fr/offre">notre offre Nubla Pro</a> !</li>
<li>avril : Nous réalisons une journée de formation en équipe sur le DDD (Domain Driven Design), une technique de conception logicielle orientée métier, animée par Bertrand Bougon.</li>
<li>mai : Un temps fort de la vie coopérative de Yaal Coop, c'est l'heure de sa toute première Assemblée Générale Ordinaire, en présence de l'ensemble de ses associé·es. 🎉</li>
<li>juin : Une petite mission démarre avec <a href="https://www.freexian.com/fr/">Freexian</a> pour retravailler son identité graphique et refondre ses deux sites web statiques ainsi que son fil d'actualités.</li>
<li>août : C'est la fin de notre mission régulière pour Sinch sur Myelefant, le projet historique de Yaal SAS racheté en 2019. Yaal Coop vole maintenant complètement de ses propres ailes !</li>
<li>septembre : Notre associé Yaal SAS est remplacé par Gruyère SAS (formé d'un sous ensemble plus réduit des anciens associés de Yaal SAS) dans le collège des investisseurs de Yaal Coop. C'est aussi le début de notre intervention sur la startup d'État <a href="https://beta.gouv.fr/startups/plateforme.impact.html">Projet Impact</a> pour lancer le développement d'une plateforme française d'aide aux entreprises à satisfaire leurs obligations réglementaires en matière de performance extra-financière.</li>
<li>octobre : Une petite mission est réalisée pour <a href="https://podeduc.apps.education.fr/">PodEduc</a>, une plateforme vidéo pour les agents de l'Éducation nationale, via deux contributions au logiciel libre Esup-Pod.</li>
<li>novembre : Notre projet interne <a href="https://canaille.yaal.coop/">Canaille</a>, logiciel libre de gestion d'identité et d'autorisations, obtient un financement de la fondation NLNet d'un montant de 7 000€ pour développer quelques fonctionnalités prévues en 2023.</li>
<li>décembre : <a href="https://nubla.fr/accueil">Nubla</a>, notre service d'hébergement e-mail et cloud, fait officiellement partie des 6 nouveaux CHATONS du Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires ! Nos services sont disponibles gratuitement sur demande aux premiers beta-testeurs. Enfin, nous préparons l'embauche de Julien qui rejoint la coopérative à la toute fin du mois pour travailler sur une mission avec NEHS Digital, éditeur de solutions santé pour améliorer l'efficience du parcours de soin.</li>
</ul>
<hr/>
<h2>Notre projet coopératif</h2>
<h3>Sociétariat</h3>
<p>Excepté Julien, arrivé le 27 décembre 2022, tous·tes les salarié·es sont également associé·es au sein de Yaal Coop sur l'année 2022 et détiennent chacun·e une voix égale au sein du collège des salarié·es, conformément à nos statuts.</p>
<p>Seul changement notable au sein des autres collèges : Yaal SAS est remplacé par Gruyère SAS dans le collège des investisseurs en septembre 2022, ce qui ne modifie pas le capital social de la coopérative.</p>
<p>Nous proposons à Colin Garriga-Salaün, le Président de Yaal SAS, de devenir associé en son nom propre dans le collège des observateurs. Celui-ci accepte en avril 2023.</p>
<p>La composition des collèges en date du 9 mai 2023 est la suivante :</p>
<ul>
<li>Collège des salariés - 50% des droits de vote</li>
</ul>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE   </th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>Brunélie LAURET</td>
<td>100</td>
</tr>
<tr>
<td>Camille DANIEL</td>
<td>100</td>
</tr>
<tr>
<td>Loan ROBERT</td>
<td>100</td>
</tr>
<tr>
<td>Stéphane BLONDON</td>
<td>100</td>
</tr>
<tr>
<td>Éloi RIVARD</td>
<td>100</td>
</tr>
</tbody>
</table>
<ul>
<li>Collège des investisseurs - 16,66% des droits de vote</li>
</ul>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE   </th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>GRUYERE</td>
<td>50 000</td>
</tr>
</tbody>
</table>
<ul>
<li>Collège des bénéficiaires - 16,66% des droits de vote</li>
</ul>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE   </th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>FINACOOP NOUVELLE-AQUITAINE</td>
<td>100</td>
</tr>
</tbody>
</table>
<ul>
<li>Collège des observateurs - 16,66% des droits de vote</li>
</ul>
<table>
<thead>
<tr>
<th>Prénom NOM / RAISON SOCIALE   </th>
<th>Nombre de parts</th>
</tr>
</thead>
<tbody>
<tr>
<td>Arthur LEDARD</td>
<td>100</td>
</tr>
<tr>
<td>Colin GARRIGA-SALAÜN</td>
<td>100</td>
</tr>
</tbody>
</table>
<p>(sous réserve de validation de l'entrée de Colin GARRIGA-SALAÜN par la prochaine Assemblée Générale)</p>
<h3>Favoriser une organisation horizontale</h3>
<h4>Mise en place d'une forme d'holacratie dans Yaal Coop</h4>
<p>Après quelques discussions et ateliers organisés en interne, nous avons décidé de nous inspirer de l'<a href="https://fr.wikipedia.org/wiki/Holacratie">holacratie</a> pour définir des rôles tournants permettant d'assurer la prise en main commune de la gouvernance de la coopérative par les salarié·es. Ces rôles nous donnent un cadre pour protéger le fonctionnement horizontal souhaité dans Yaal Coop et nous protéger de la spécialisation des associé·es salarié·es.</p>
<p>Le système, la pertinence et la répartition des rôles sont améliorés au fil du temps, à chaque nouvelle réunion de gouvernance du collège des salarié·es, actuellement organisée tous les 3 mois.</p>
<p>Depuis sa mise en place, nous avons notamment fait la révision de la durée de certains rôles (pouvant aller de 2 semaines pour le rôle de Facteur·rice 💌 -<em>qui relève le courrier entrant sur nos différentes boîtes aux lettres</em>- ou Sentinelle 📟 -<em>qui surveille et réagit aux alertes de monitoring</em>-, à 2 ans avec backup pour le rôle d'Argentier·e 🪙 -<em>qui met à jour et surveille la trésorerie</em>-). Nous avons également ajouté des précisions sur les attentes d'autres rôles lors de ces réunions, en questionnant les manquements auxquels nous avons pu faire face.</p>
<p>Ces réunions de gouvernance viennent en complément de nos réunions de suivi hebdomadaire lors desquelles nous faisons le point sur l'ensemble des tâches et projets en cours dans la coopérative.</p>
<p>Enfin des réunions de stratégie sur l'investissement réunissent également le collège des salarié·es tous les 3 mois pour faire le bilan de l'investissement réalisé au trimestre précédent et fixer les priorités du trimestre suivant.</p>
<h4>Changement de présidence proposé en 2023</h4>
<p>Les mandats concernant la présidence et la direction générale de la coopérative sont établis statutairement pour une durée de 4 ans. Nous avons décidé de mettre fin prématurément à ceux courant depuis le lancement de la coopérative en septembre 2020 afin de renforcer une représentativité et une responsabilité tournante au sein de Yaal Coop. Nous vous proposons donc d'élire notre nouvelle Présidente, Brunélie, dès la prochaine AGO !</p>
<h3>Favoriser l'activité et les acteurs ayant un impact social ou environnemental, de préférence locaux</h3>
<h4>Investissement technique</h4>
<p>Nous sommes toujours associés avec <a href="https://lum1.fr/">Lum1</a>, premier annuaire collaboratif dédié et réservé aux professionnels du social et de la santé, projet pour lequel nous effectuons du développement en continu, à un rythme plus réduit que lors du développement intensif de la deuxième version de la plateforme l'année précédente.</p>
<p>En 2022, nous n'avons pas signé de nouveau projet associé, toutefois certains de nos prospects montrent de l'intérêt pour cette forme de coopération qui permet d'aller au delà du lien unissant prestataire et client.</p>
<h4>Investissement interne</h4>
<p>Notre projet <a href="https://nubla.fr/a-propos">Nubla</a>, développé en interne, est un service d'hébergement cloud membre des CHATONS (Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires) depuis décembre 2022. Son ambition est de proposer un service basé sur des solutions libres pour permettre à tous et toutes de se libérer des géants du web afin de mieux maîtriser l'utilisation de ses données et de soutenir l'écosystème numérique local.</p>
<h4>Économie Sociale et Solidaire (ESS)</h4>
<p>Parmi nos clients, conformément à nos engagements en tant que SCIC, figurent des acteurs de l'économie solidaire et sociale comme Telecoop.</p>
<p>Nous avons également été en contact et en discussion avec d'autres acteur·ices de ce milieu comme prospects, sans forcément aboutir à une prestation.</p>
<p>En 2022 nous avons souscrit des parts chez plusieurs de nos fournisseurs coopératifs : notre banque Crédit Coopératif et notre cabinet de paie <a href="https://www.assistea-paie.com/">Assistea</a>, ainsi que <a href="https://telecoop.fr/">Telecoop</a>, notre fournisseur téléphonique mobile et notre client sur une mission du premier semestre 2022.</p>
<h4>BetaGouv et direction du numérique pour l'éducation</h4>
<p>Toutes nos prestations ne sont pas du domaine de l'ESS, mais en 2022, nous avons multiplié les prestations pour des projets de l'État (La startup d'État <a href="https://beta.gouv.fr/startups/plateforme.impact.html">Projet Impact</a> développée par la direction générale des entreprises en lien avec BetaGouv, le <a href="https://webinaire.numerique.gouv.fr/home">frontal de visioconférence B3Desk</a> et la plateforme de vidéos <a href="https://podeduc.apps.education.fr/">PodEduc</a> portés par la direction du numérique pour l'éducation).</p>
<p>Via ces missions, nous pouvons espérer participer à l'amélioration des services publics impactés par ces réalisations, sur du code source libre.</p>
<p>Ces missions qui se poursuivent en 2023 nous permettent en outre d'assurer une certaine pérennité dans l'activité et les revenus de Yaal Coop, et participent à l'étendue de notre réseau de clients et au rayonnement de la coopérative dans le milieu.</p>
<h4>Acteurs locaux</h4>
<p>Tous nos clients et prospects ne sont pas des acteurs locaux, mais une partie sont bien basés à Bordeaux. Notre client Lum1 et plusieurs de nos prospects sur l'année étaient des organismes bordelais ou girondins.</p>
<p>Nubla, notre service d'hébergement cloud membre des CHATONS, voit une bonne part de ses utilisateurs situés dans la région, que ce soit sur l'offre publique ou sur l'offre Pro. Notre communication et nos ambitions s'orientent en partie sur son aspect local et souverain.</p>
<h4>Impact environnemental</h4>
<p>Comme beaucoup, nous sommes sensibles aux enjeux environnementaux et tentons de limiter à notre échelle l'impact environnemental de la coopérative.</p>
<p>La question du numérique soutenable est une question de plus en plus posée. En tant que société informatique, nous sommes évidemment concernés. Plutôt qu'un greenwashing de façade, nous nous concentrons aujourd'hui sur des actions concrètes :</p>
<ul>
<li>le choix des projets sur lesquels nous travaillons, qu'on souhaite le plus possible porteurs de sens et proches des valeurs que nous défendons. Le premier levier pour diminuer l'impact environnemental du numérique est avant tout de ne PAS construire des produits ou des fonctionnalités inutiles, irresponsables, ou incompatibles avec le matériel existant.</li>
<li>limiter le renouvellement de notre matériel informatique en privilégiant en 2022 la réparation d'un de nos ordinateurs plutôt que son remplacement, l'achat d'un serveur d'occasion pour compléter notre infrastructure et le remplacement de ventilateurs défectueux par du matériel d'occasion sur un serveur existant.</li>
</ul>
<p>La séance de projection du documentaire libre <a href="https://naos-cluster.com/2022/07/08/sortie-officielle-du-documentaire-responsables-du-numerique/">"Responsables du Numérique"</a> produit par Nouvelle-Aquitaine Open Source (NAOS) en juillet 2022 nous a confortés dans l'importance de ces choix et le rôle à jouer du logiciel libre.</p>
<h4>Réseau Libre Entreprise</h4>
<p>Le réseau <a href="https://www.libre-entreprise.org/">Libre-entreprise</a> regroupe des entreprises à taille humaine ayant des spécialités proches ou complémentaires dans le domaine du logiciel libre. Ces entreprises partagent des valeurs et modes de fonctionnement proches des nôtres, basés sur la démocratie d'entreprise, la transparence et la compétence. C'est pourquoi nous avons candidaté à les rejoindre dans l'espoir de pouvoir s'aider mutuellement. Nous sommes actuellement en période d'observation. Cette période est un préalable obligatoire avant d'être validé par les membres du réseau Libre-entreprise.</p>
<h3>Favoriser l'utilisation et le développement de logiciels libres</h3>
<p>L'ensemble de nos contributions à des logiciels libres sont visibles sur ces différents articles de blog, publiés de façon saisonnière :</p>
<ul>
<li><a href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-debut-2022">Contributions début 2022</a></li>
<li><a href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2022">Contributions été 2022</a></li>
<li><a href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2022">Contributions automne 2022</a></li>
</ul>
<p>Au delà de ces contributions, la valorisation du logiciel libre est une valeur forte de la coopérative, que ce soit dans le choix même de nos missions de prestation (BetaGouv, Freexian, etc.) ou le développement de notre projet interne Nubla.</p>
<p>Pour appuyer cet attachement, nous avons adhéré en juillet 2022 à <a href="https://naos-cluster.com/">Nouvelle-Aquitaine Open Source (NAOS)</a>, un pôle de compétences régional en logiciels et technologies libres et open source.
Son objectif est de promouvoir le développement d’une filière économique pour les technologies libres et open source sur le territoire de la région Nouvelle-Aquitaine.</p>
<p>Enfin en novembre 2022, nous avons contribué financièrement à hauteur de 500€ à l'<a href="https://www.afpy.org/">AFPy (Association Francophone Python)</a> pour sponsoriser l'organisation de l'édition 2023 de la PyconFR qui a eu lieu du 16 au 19 février 2023 à Bordeaux. La PyconFR est une conférence nationale gratuite dédiée au regroupement des personnes intéressées par le langage de programmation Python, principal langage utilisé au sein de la coopérative.</p>
<hr/>
<h2>Bilan financier et compte de résultat 2022</h2>
<p>Comme nous nous y attendions, le résultat du bilan 2022 est nettement en deça de celui du premier exercice comptable de 2020-2021 avec un chiffre d'affaires de 220 028€. La fin du contrat avec Sinch, le ralentissement du rythme de développement de Lum1 et la plus petite durée de l'exercice comptable (12 mois versus 16, dont 14 mois d'activité lors du précédent exercice) en sont les principales raisons.</p>
<p>Il est tout de même excédentaire avec un résultat net comptable de 46 987€. Ce bénéfice est toutefois à nuancer par l'annulation de 42 492€ de produits constatés d'avance de l'exercice précédent (règlements perçus d'avance lors de l'exercice précédent et comptabilisés en 2022). Nous n'avons pas enregistré de nouveaux produits constatés d'avance pour le prochain exercice. Sur la base de ce résultat encore fragile, nous n'avons pas jugé raisonnable d'augmenter les salaires comme nous avions envisagé de le faire, et ce malgré l'inflation.</p>
<p>Le détail du bilan est disponible dans les comptes annuels 2022 rédigés par notre cabinet d'expertise comptable Finacoop.</p>
<p>Conformément à la dernière décision d'Assemblé Générale, l'intégralité du bénéfice 2022 est affecté aux réserves impartageables de la coopérative, dont 15% à la réserve légale.</p>
<p>Aucun dividende n'a été versé depuis le premier exercice comptable de Yaal Coop et les dirigeants ne touchent aucune rémunération liée à leur statut de dirigeant.</p>
<hr/>
<h2>Perspectives</h2>
<p>L'exercice 2023 a commencé et devrait se poursuivre en continuité avec la fin de l'exercice 2022 : les principales missions pour l'État ont été reconduites (Projet Impact, B3Desk) et le développement de Lum1 se poursuit à un rythme plus réduit. En parallèle des discussions s'engagent ou se poursuivent avec plusieurs prospects.</p>
<p>Le financement de NLNet pour le développement de notre logiciel libre Canaille va nous permettre de le faire évoluer pour favoriser son adoption par d'autres acteurs. Nous sommes également en recherche de financement pour finaliser notre solution Nubla et son ouverture au grand public !</p>
<p>Le déménagement de Yaal Coop dans <a href="https://yaal.coop/local">nos futurs locaux</a> à Bègles est prévu pour l'été 2023 ! La gestion des travaux et la recherche de futurs colocataires se poursuivent.</p>
<p>Enfin, nous avons l'ambition d'un meilleur résultat pour 2023, en vue d'augmenter collectivement les salaires, sans quoi nous mettrions en doute la réussite de notre projet coopératif.</p>
<hr/>
<h2>Conclusion</h2>
<p>Nous espérons que les résolutions qui vous sont proposées recevront votre agrément et que vous voudrez bien donner au Président et à la Directrice Générale quitus de leur gestion pour l’exercice écoulé.</p>
<p>Rédigé collectivement par l'équipe salariée de Yaal Coop,
Signé par Éloi Rivard, Président de Yaal Coop, et Camille Daniel, Directrice Générale de Yaal Coop.</p>
            </div>
        </content>
        <author>
            <name>Camille Daniel &lt;camille@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Création du jeu Flipping Bits en Python avec une IHM en Tkinter</title>
        <link href="https://www.ssaurel.com/blog/creating-a-flipping-bits-game-in-python-with-tkinter/" />
        <id>https://www.ssaurel.com/blog/creating-a-flipping-bits-game-in-python-with-tkinter/</id>
        <updated>2023-05-09T12:42:41Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ce tutoriel vous montrera comment créer une version Python du jeu Flipping Bits avec une IHM en Tkinter.</p>
<a href="https://news.humancoders.com/t/python/items/20454-creation-du-jeu-flipping-bits-en-python-avec-une-i"><img src="https://www.ssaurel.com/blog/wp-content/uploads/2023/05/FlippingBits-initial-1024x744.jpg"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20454-creation-du-jeu-flipping-bits-en-python-avec-une-i#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20454-creation-du-jeu-flipping-bits-en-python-avec-une-i">Création du jeu Flipping Bits en Python avec une IHM en Tkinter</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>ssaurel</name>
        </author>
    </entry>
    <entry>
        <title>Création d&#39;un programme de génération de fichier Sitemap en Python</title>
        <link href="https://www.ssaurel.com/blog/learn-to-create-a-sitemap-file-generator-in-python/" />
        <id>https://www.ssaurel.com/blog/learn-to-create-a-sitemap-file-generator-in-python/</id>
        <updated>2023-05-04T14:49:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ce tutoriel décrit la création pas à pas d’un programme de génération de fichier Sitemap en Python.</p>
<a href="https://news.humancoders.com/t/python/items/20450-creation-d-un-programme-de-generation-de-fichier-s"><img src="https://www.ssaurel.com/blog/wp-content/uploads/2023/05/sitemap_format-1024x982.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20450-creation-d-un-programme-de-generation-de-fichier-s#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20450-creation-d-un-programme-de-generation-de-fichier-s">Création d'un programme de génération de fichier Sitemap en Python</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>ssaurel</name>
        </author>
    </entry>
    <entry>
        <title>Panda vs Numpy</title>
        <link href="https://www.olivierpons.fr/2023/05/02/panda-vs-numpy/" />
        <id>https://www.olivierpons.fr/2023/05/02/panda-vs-numpy/</id>
        <updated>2023-05-02T23:23:23Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>Ce qu’il faut retenir</h1>
<p>Numpy et Pandas n’ont pas exactement les mêmes objectifs.</p>
<p>Dans la plupart des cas, NumPy peut être légèrement plus rapide que pandas, car <strong>NumPy est plus bas niveau et a moins de surcharge</strong>. Cependant, pandas offre des structures de données et des fonctionnalités plus avancées, ce qui peut faciliter le travail avec des ensembles de données complexes. <strong>Les performances relatives de NumPy et pandas dépendent également des opérations spécifiques effectuées sur les données</strong>, de sorte que les différences de performances peuvent varier en fonction des tâches spécifiques. Certaines fonctions n’existent qu’avec pandas, et qui n’ont pas d’équivalents NumPy sont : <code>read_csv</code>, <code>read_excel</code>, <code>groupby</code>, <code>pivot_table</code>, <code>merge</code>, <code>concat</code>, <code>melt</code>, <code>crosstab</code>, <code>cut</code>, <code>qcut</code>, <code>get_dummies</code> et <code>applymap</code>.</p>
<h1>Résultats</h1>
<p>Résultat : image générée : notez bien que j’ai appelé des fonctions « bas niveau » pour qu’on voie ce que NumPy a dans le ventre et des fonctions qui n’existent que dans pandas, que ré-implémentées en Python pur + NumPy.</p>
<p><a href="https://www.olivierpons.fr/download/2023-04-02_15h35m12s_pandas_vs_numpy.png" rel="noopener noreferrer" target="_blank"><img alt="Résultats pandas vs NumPy" src="https://www.olivierpons.fr/download/2023-04-02_15h35m12s_pandas_vs_numpy.png" title="Résultats pandas vs NumPy"/></a></p>
<h1>Code source</h1>
<p>Voici le code source que j’ai fait, qui appelle quelques fonctions connues de NumPy et de pandas.</p>
<pre style="font-size: 70%; line-height: normal;">import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt

# Générer un grand ensemble de données
data_np = np.random.rand(30_000_000)
data_pd = pd.DataFrame({"values": data_np})

operations = (
    "sum",
    "mean",
    "filter",
    "cum_sum",
    "sort",
    "complex",
    "pivot",
    "group_by",
    "rolling",
)
time_np = []
time_pd = []


# Définir une fonction pour chronométrer et stocker les temps d'exécution
def measure_time(start_time, end_time, time_list):
    time_list.append(end_time - start_time)


# Effectuer les différentes opérations et mesurer les temps d'exécution
for operation in operations:
    # print(f"operation: {operation}")
    print(f"{operation}")
    if operation == "sum":
        start_time_np = time.time()
        result_np = np.sum(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        result_pd = data_pd["values"].sum()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "mean":
        start_time_np = time.time()
        mean_np = np.mean(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        mean_pd = data_pd["values"].mean()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "filter":
        start_time_np = time.time()
        filtered_np = data_np[data_np &gt; 0.5]
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        filtered_pd = data_pd[data_pd["values"] &gt; 0.5]
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "cum_sum":
        start_time_np = time.time()
        cum_sum_np = np.cumsum(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        cum_sum_pd = data_pd["values"].cumsum()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "sort":
        start_time_np = time.time()
        sorted_np = np.sort(data_np)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        start_time_pd = time.time()
        sorted_pd = data_pd["values"].sort_values()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)
    elif operation == "complex":
        # Générer des données structurées
        data_1 = np.random.randint(0, 1_000_000, (2_000, 2))
        data_2 = np.random.randint(0, 1_000_000, (2_000, 2))

        # Créer des DataFrames pandas
        df_1 = pd.DataFrame(data_1, columns=["id", "value_1"])
        df_2 = pd.DataFrame(data_2, columns=["id", "value_2"])

        # Créer des arrays structurés NumPy
        d_type = np.dtype([("id", int), ("value", int)])
        numpy_data_1 = np.array(
            list(map(tuple, data_1)), dtype=d_type
        )
        numpy_data_2 = np.array(
            list(map(tuple, data_2)), dtype=d_type
        )

        # Jointure avec NumPy
        def numpy_join(data1, data2):
            result = []
            for row1 in data1:
                for row2 in data2:
                    if row1["id"] == row2["id"]:
                        result.append(
                            (row1["id"], row1["value"], row2["value"])
                        )
            return np.array(
                result,
                dtype=[
                    ("id", int),
                    ("value_1", int),
                    ("value_2", int),
                ],
            )

        start_time_np = time.time()
        numpy_result = numpy_join(numpy_data_1, numpy_data_2)
        end_time_np = time.time()
        measure_time(
            start_time_np, end_time_np, time_np
        )  # Ajoutez cette ligne

        # Jointure avec pandas
        start_time_pd = time.time()
        pandas_result = df_1.merge(df_2, on="id")
        end_time_pd = time.time()

        measure_time(start_time_pd, end_time_pd, time_pd)
    elif operation == "pivot":
        # Générer des données structurées
        unique_ids = np.arange(0, 60_000)
        unique_groups = np.arange(0, 3)
        id_col = np.repeat(unique_ids, len(unique_groups))
        group_col = np.tile(unique_groups, len(unique_ids))
        value_col = np.random.randint(0, 100, len(id_col))
        data = np.column_stack((id_col, group_col, value_col))

        # Créer des DataFrames pandas
        df = pd.DataFrame(data, columns=["id", "group", "value"])

        # Créer des arrays structurés NumPy
        d_type = np.dtype(
            [("id", int), ("group", int), ("value", int)]
        )
        numpy_data = np.array(list(map(tuple, data)), dtype=d_type)

        # Pivot avec NumPy
        def numpy_pivot(_data, _id_col, _group_col, _value_col):
            _unique_ids = np.unique(_data[_id_col])
            _unique_groups = np.unique(_data[_group_col])

            pivot_table = np.zeros(
                (len(_unique_ids), len(_unique_groups))
            )


            for row in _data:
                id_index = np.where(_unique_ids == row[_id_col])[0][0]
                group_index = np.where(
                    _unique_groups == row[_group_col]
                )[0][0]
                pivot_table[id_index, group_index] = row[_value_col]

            return pivot_table

        start_time_np = time.time()
        numpy_pivot_table = numpy_pivot(
            numpy_data, "id", "group", "value"
        )
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        # Pivot avec pandas
        start_time_pd = time.time()
        pandas_pivot_table = df.pivot(
            index="id", columns="group", values="value"
        )
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "group_by":
        # Générer des données structurées
        data = np.random.randint(0, 10_000_000, (100_000, 2))

        # Créer des DataFrames pandas
        df = pd.DataFrame(data, columns=["id", "value"])

        # Créer des arrays structurés NumPy
        d_type = np.dtype([("id", int), ("value", int)])
        numpy_data = np.array(list(map(tuple, data)), dtype=d_type)

        # Group_by avec NumPy
        def numpy_group_by_mean(_data):
            _unique_ids, counts = np.unique(
                _data["id"], return_counts=True
            )
            sums = np.zeros_like(_unique_ids, dtype=float)
            for row in _data:
                sums[np.where(_unique_ids == row["id"])[0][0]] += row[
                    "value"
                ]
            return _unique_ids, sums / counts

        start_time_np = time.time()
        numpy_result = numpy_group_by_mean(numpy_data)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        # Group_by avec pandas
        start_time_pd = time.time()
        pandas_result = df.groupby("id")["value"].mean()
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

    elif operation == "rolling":
        # Générer un grand ensemble de données
        data_np = np.random.rand(100_000_000)
        data_pd = pd.DataFrame({"values": data_np})

        window = 100

        def numpy_rolling_mean(arr, _window):
            _cum_sum = np.cumsum(np.insert(arr, 0, 0))
            return (
                _cum_sum[_window:] - _cum_sum[:-_window]
            ) / _window

        start_time_np = time.time()
        numpy_result = numpy_rolling_mean(data_np, window)
        end_time_np = time.time()
        measure_time(start_time_np, end_time_np, time_np)

        # Rolling avec pandas
        start_time_pd = time.time()
        pandas_result = (
            data_pd["values"].rolling(window=window).mean()
        )
        end_time_pd = time.time()
        measure_time(start_time_pd, end_time_pd, time_pd)

# Créer un graphique de comparaison
x = np.arange(len(operations))
width = 0.35

fig, ax = plt.subplots()

rects1 = ax.bar(
    x - width / 2,
    time_np,
    width,
    label="NumPy",
    color="#c9daf8",
    edgecolor="black",
    hatch="//",
    linewidth=1,
)
rects2 = ax.bar(
    x + width / 2,
    time_pd,
    width,
    label="pandas",
    color="#c2e8b8",
    edgecolor="black",
    hatch=".",
    linewidth=1,
    alpha=0.5,
)


# Modification de la taille des marqueurs dans rects2
for rect in rects2:
    rect.set_linewidth(2)

ax.set_yscale("log")
ax.set_ylabel("Temps d'exécution (s) - Échelle logarithmique")
ax.set_title(
    "Comparaison des temps d'exécution entre NumPy et pandas"
)
ax.set_xticks(x)
ax.set_xticklabels(operations)
ax.legend()


def autolabel(rects):
    for _rect in rects:
        height = _rect.get_height()
        ax.annotate(
            "{:.2f}".format(height),
            xy=(_rect.get_x() + _rect.get_width() / 2, height),
            xytext=(0, 3),  # 3 points vertical offset
            textcoords="offset points",
            ha="center",
            va="bottom",
        )


autolabel(rects1)
autolabel(rects2)

fig.tight_layout()
plt.savefig("pandas_vs_numpy.png")</pre>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Visite à la PyConFR 2023</title>
        <link href="https://yaal.coop/blog/pyconfr-2023" />
        <id>https://yaal.coop/blog/pyconfr-2023</id>
        <updated>2023-04-10T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://www.pycon.fr/2023/">La conférence PyConFR</a> est constituée de deux jours de sprints puis deux jours de conférences. Cette année elle a eu lieu à Bordeaux, l'occasion pour Yaal Coop de s'y rendre à plusieurs et de sponsoriser l'évènement pour soutenir l'organisation.</p>
<p>Les sprints sont l'occasion de découvrir des projets écrits en Python, mettre le pied à l'étrier pour les utiliser, idéalement, réussir à faire quelques contributions dessus. Ce fut l'occasion de tester <a href="https://github.com/cgwire/zou">zou</a> ainsi qu'avoir une Pull Request acceptée sur cpython (merci à <a href="https://mdk.fr/">Julien Pallard</a>) et d'en faire une autre, suite à la précédente. :)</p>
<p>C'est aussi l'occasion de rencontrer et discuter dans les allées avec d'autres pythonistes.</p>
<p>Lors de la seconde partie de la PyCon, plusieurs conférences se déroulaient en même temps, dans les amphithéatres différents. Parmi celles que nous avons vues:</p>
<h2>Django Admin comme framework pour développer des outils internes</h2>
<p>Il est possible d'adapter l'interface d'admin de django pour créer des applications CRUD pour un usage interne. L'intérêt est de gagner du temps en utilisant la capacité de django-admin à produire des interfaces listant et modifiant des objets rapidemment. Parmi les astuces et personnalisation, on notera :</p>
<ul>
<li>la possibilité de modifier le nom 'Django admin' dans l'interface de connexion pour rassurer les utilisateurs</li>
<li>l'utilisation de 'create views' dans un script de migration permettant de faire des visualisations en lecture seule.</li>
</ul>
<p>Le présentateur indique que, si le besoin devient plus complexe par la suite, la solution est de passer au developpement classique d'un service django.</p>
<h2>Uncovering Python’s surprises: a deep dive into gotchas</h2>
<p>Une présentation en anglais montrant des curiosités plus ou moins connues du langage. Une partie des exemples sont issus de <a href="https://github.com/satwikkansal/wtfpython#structure-of-the-examples">wtfpython</a>.</p>
<h2>Faire du Python professionnel</h2>
<p>Typer ou ne pas typer en python, telle est la question... Plusieurs conférences ont abordé le sujet, dont celle-ci. Globalement ses avantages semblent faire de plus en plus consensus au sein de la communauté. Une référence d'<a href="https://dev.to/etenil/why-i-stay-away-from-python-type-annotations-2041">article de blog</a> intéressante néanmoins, avec des arguments contre les annotations de type.</p>
<p>Et un conseil pertinent : ne pas faire d'annotation sans mettre en place un outil (type mypy) dans la CI pour les vérifier. 😇</p>
<h2>Portage Python sur Webassembly</h2>
<p>WebAssembly est un langage fonctionnant dans les navigateurs. Il est possible d'écrire du code Python et de le convertir en WebAssembly. Arfang3d est un moteur 3D qui fonctionne ainsi.</p>
<p>python -m asyncio -&gt; pour avoir un shell python asynchone</p>
<p>C'est aussi un moyen de convertir des jeux écrits avec pygame pour les exécuter dans un navigateur. Une liste de jeu compatible est disponible sur <a href="https://pygame-web.github.io/">pygame-web.github.io</a>.</p>
<h2>Fear the mutants. Love the mutants.</h2>
<p>Comment être sûr que les tests vérifient bien ce qu'ils sont censés vérifier ?
<a href="https://pypi.org/project/mutmut/">mutmut</a> modifie le code source à tester et vérifie que les tests sont en erreur après la modification. La commande principale est <code>mutmut run</code>.
Pour changer le comportement du code, <code>mutmut</code> accède et modifie l'AST (<strong>Abstact Syntax Tree</strong>) grâce à la bibliothèque <a href="https://pypi.org/project/parso/">parso</a>.</p>
<h2>Python moderne et fonctionnel pour des logiciels robustes</h2>
<p>Il s'agissait ici de s'inspirer de quelques principes et règles souvent utilisées dans le fonctionnel pour pouvoir coder en python de façon plus propre des services plus résistants et moins endettés.</p>
<p>Il a été question de typage avec les hints de Mypy mais aussi avec <a href="https://github.com/microsoft/pyright">Pyright</a>, moins permissif et donc contraignant à des règles de propreté. Avec Python3.8 sont arrivés les Protocols, un cas spécifique d'utilisation des Abstract Base Classes sans héritage où il suffit de reproduire une signature.</p>
<p>Faire remonter les impuretés et les effets de bord a également été abordé avec l'architecture en oignon (comme la connexion à la persistance, les modifications à sauvegarder, les configurations, etc.) avec l'idée de pouvoir tester le cœur de son code sans dépendre de tout un environnement.</p>
<p>Le paramètre <code>frozen</code> du décorateur <code>@dataclass(frozen=True)</code> permet de rendre les instances immutables.</p>
<p>La classe <code>typing.Protocol</code>, décrite dans la <a href="https://peps.python.org/pep-0544/">PEP 544</a> et introduite dans Python 3.8 permet de définir des interfaces.</p>
<p>Une recommandation de vidéo : <a href="https://www.youtube.com/watch?v=US8QG9I1XW0">Functional architecture - The pits of success - Mark Seemann</a></p>
<h2>Accessibilité numérique : faire sa part quand on est développeur·euse backend</h2>
<p>Une introduction aux problématiques de l'accessibilité avec une <a href="https://www.youtube.com/watch?v=EtVCVu8E0ng">démo percutante en vidéo</a> de l'expérience que peut avoir une personne aveugle en naviguant sur internet.
Saviez vous qu'aujourd'hui, 1 personne sur 5 était en situation de handicap ?
L'objectif était ici de sensibiliser le public, en majorité des développeurs back-end, aux questions d'accessibilité, et d'appuyer le fait que ce n'était pas qu'une question réservée aux design ou au front.</p>
<p>Quelques petites choses glanées :</p>
<ul>
<li>quand on construit une plateforme diffusant du contenu utilisateur, prévoir l'ajout possible d'un texte alternatif/de sous titres à stocker avec l'image/la vidéo de l'utilisateur</li>
<li>se méfier des inputs utilisateurs que certains arriveront à détourner pour mettre du contenu en forme (des émojis, des caractères mathématiques...) qui sera ensuite illisible pour les lecteurs d'écrans</li>
<li>l'attribut html <code>lang</code> peut être utilisé avec n'importe quelle balise, pas seulement dans l'en-tête de la page, pour signaler une citation dans une langue étrangère par exemple ! Cela permet aux logiciels de lecture d'écran d'adopter la bonne prononciation 🤯</li>
<li>préferer le server side rendering et faire de la mise en cache pour accélerer l'affichage : un loader à l'écran n'est pas forcément explicite pour tous les utilisateurs (ou lecteurs...)</li>
<li>FALC (Facile à lire et à comprendre) est une méthode/un ensemble de règles ayant pour finalité de rendre l'information facile à lire et à comprendre, notamment pour les personnes en situation de handicap mental</li>
</ul>
<p>Sensibiliser les producteurs d'une part significative des mediums d'information est toujours une bonne chose.</p>
<h2>Interactive web pages with Django or Flask, without writing JavaScript</h2>
<p><a href="https://htmx.org/">htmx</a> est une bibliothèque javascript dont le but est de permettre la fourniture de code HTML qui sera intégré dans le DOM. L'idée est de remplacer le code javascript as-hoc et les transferts en JSON (ou autre). Si le principe semble adapté à certains cas, il ne remplacera pas de gros framework produisant des Single Page App.</p>
<p><a href="https://docs.pyscript.net/">pyScript</a> est un projet encore très jeune qui permet l'exécution de code Python dans le navigateur.</p>
<p>Merci à l'équipe de bénévoles pour l'organisation de la conférence. À l'année prochaine !</p>
            </div>
        </content>
        <author>
            <name>Stéphane Blondon &lt;stephane@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Contributions à des logiciels libres par l&#39;équipe Yaal Coop durant l&#39;hiver 2023</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2023" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-hiver-2023</id>
        <updated>2023-03-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Cet hiver nous avons surtout travaillé sur <a href="https://canaille.yaal.coop">Canaille</a> pour préparer l'implémentation de fonctionnalités sponsorisées par la <a href="https://nlnet.nl/">fondation NLNet</a>.</p>
<h2>Documentation</h2>
<ul>
<li>Python : <a href="https://github.com/python/cpython/pull/101963">suppression ou mise-à-jour de liens vers bitbucket.org</a></li>
<li>Celery : corrections d'URL (<a href="https://github.com/celery/celery/pull/8111">1</a> et <a href="https://github.com/celery/celery/pull/8112">2</a>)</li>
</ul>
<h2><a href="https://github.com/EsupPortail/Esup-Pod">Esup-Pod</a></h2>
<p><em>Plateforme de partage vidéo pensée pour l'enseignement et la recherche</em></p>
<p>Contributions financées par la <a href="https://www.education.gouv.fr/direction-du-numerique-pour-l-education-dne-9983">Direction du Numérique pour l'Éducation</a> (pôle <a href="https://foad.phm.education.gouv.fr/fr">Formation Ouverte et A Distance</a>)</p>
<ul>
<li><a href="https://github.com/EsupPortail/Esup-Pod/pull/693">Proxy configurable par variable d'environnement</a></li>
<li><a href="https://github.com/EsupPortail/Esup-Pod/pull/694">Configuration d'une affiliation pour les utilisateurs connectés par OIDC</a></li>
</ul>
<h2><a href="https://www.systeme-de-design.gouv.fr/">DSFR</a></h2>
<p><em>Système de design de l’État</em></p>
<ul>
<li><a href="https://github.com/GouvernementFR/dsfr/pull/518">Rend le composant Interrupteur compatible avec vite+svelte</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/82">Correction d'un paramètre de retour lors de la déconnexion OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/83">Cohérence des valeurs entre les claims OIDC et JWT</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/86">Formulations et ponctuations</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/87">Correction de l'attribut HTML de langue</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/89">Mail de test de connectivité</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/90">Mise à jour des dépendances Javascript</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/91">Suppression automatiques des espaces autour des phrases de traductions</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/92">Réusinages du modèle de données LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/">Corrections relative à l'enregistrement automatique de clients</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/98">La supression de clients supprime les objets liés</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/100">Suppression des jetons</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/102">Liens vers les pages légales sur les consentements des utilisateurs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/103">Correction d'un message dans le script de lancement de la démo</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/104">Affichage des applications pré-autorisées</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/106">Commande de génération de groupes et d'utilisateurs aléatoires</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/109">D'autres réusinages du modèle de données LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/111">Pagination et recherche côté serveur</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/112">Support de l'édition des adresses</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/113">Support de l'édition du champ « titre »</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/114">Ajout d'un sous-menu</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/116">Support de l'édition du champ « organization »</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/117">Mise en cache des avatars</a></li>
</ul>
<h2><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h2>
<p><em>Plugin OpenID Connect pour nextcloud</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/220">Pas de téléchargement des avatars s'ils n'ont pas été modifiés</a></li>
</ul>
<h2><a href="https://github.com/azmeuk/flask-shell-ptpython">flask-shell-ptpython</a></h2>
<p><em>Utilisation de l'interpréteur de commandes ptpython dans flask</em></p>
<ul>
<li><a href="https://github.com/jacquerie/flask-shell-ptpython/issues/18">Fork (temporaire) du projet pour cause d'abandon</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Bibliothèque python de gestion des identités et des accès</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/514">Suppression de code inutilisé</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/763">Mise à jour de pre-commit</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/764">Support de python 3.11</a></li>
</ul>
<h2><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h2>
<p><em>Intégration de WTForms dans Flask</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/539">Correction des tests unitaires</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/540">Arrêt du support de flask-babelx</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/541">Mise à jour de pre-commit</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/542">Support de python 3.11</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/546">Publication de la version 1.1.0</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/549">Correction des tests unitaires avec Flask-Babel 3</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/550">Ignore d'avertissements avec flake8</a></li>
</ul>
<h2><a href="https://github.com/python-caldav/caldav">python-caldav</a></h2>
<p><em>Bibliothèque python pour le protocole CalDAV</em></p>
<ul>
<li><a href="https://github.com/python-caldav/caldav/pull/242">Support de python 3.11</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/546">Support de l'authentification par jeton</a></li>
</ul>
<h2><a href="https://github.com/bamthomas/aioimaplib">aioimaplib</a></h2>
<p><em>Bibliothèque python asyncio IMAP4rev1</em></p>
<ul>
<li><a href="https://github.com/bamthomas/aioimaplib/pull/86">Migration de <code>setup.py</code> à <code>setup.cfg</code></a></li>
<li><a href="https://github.com/bamthomas/aioimaplib/pull/88">Assertions pythoniques dans les tests unitaires</a></li>
</ul>
<h2><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h2>
<p><em>Composant svelte de suggestion d'éléments dans une liste déroulante</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/197">Le menu reste fermé quand le champ est verrouillé</a></li>
</ul>
<h2><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h2>
<p><em>Interface pythonique pour contrôler un serveur OpenLDAP</em></p>
<ul>
<li><a href="https://github.com/python-ldap/python-slapd/pull/6">Support de python 3.11</a></li>
<li><a href="https://github.com/python-ldap/python-slapd/pull/7">Augmentation par défaut de la taille de la base de données</a></li>
</ul>
<h2><a href="http://supervisord.org/">supervisord</a></h2>
<p><em>Un gestionnaire de processus écrit en Python</em></p>
<ul>
<li><a href="https://github.com/Supervisor/supervisor/pull/1583">Suppression d'une condition python3.3</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>FOSS contributions from the Yaal Coop team during winter 2023</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2023" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-hiver-2023</id>
        <updated>2023-03-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>This winter we have mainly worked on <a href="https://canaille.yaal.coop">Canaille</a> in order to prepare the implementation of features sponsored by the <a href="https://nlnet.nl/">NLNet foundation</a>.</p>
<h2>Documentation</h2>
<ul>
<li>Python : <a href="https://github.com/python/cpython/pull/101963">remove or update bitbucket.org links</a></li>
<li>Celery : URLs fixed (<a href="https://github.com/celery/celery/pull/8111">1</a> et <a href="https://github.com/celery/celery/pull/8112">2</a>)</li>
</ul>
<h2><a href="https://github.com/EsupPortail/Esup-Pod">Esup-Pod</a></h2>
<p><em>Video sharing website aimed at education and research</em></p>
<p>Contributions funded by the <a href="https://www.education.gouv.fr/direction-du-numerique-pour-l-education-dne-9983">Direction du Numérique pour l'Éducation</a> (<a href="https://foad.phm.education.gouv.fr/fr">Formation Ouverte et A Distance</a> service)</p>
<ul>
<li><a href="https://github.com/EsupPortail/Esup-Pod/pull/693">Configurable proxy environment variable</a></li>
<li><a href="https://github.com/EsupPortail/Esup-Pod/pull/694">Configurable default affiliation for OIDC authentication</a></li>
</ul>
<h2><a href="https://www.systeme-de-design.gouv.fr/">DSFR</a></h2>
<p><em>French State design system</em></p>
<ul>
<li><a href="https://github.com/GouvernementFR/dsfr/pull/518">Fix Toggle component compatibility with vite+svelte</a></li>
</ul>
<h2><a href="https://gitlab.com/yaal/canaille">canaille</a></h2>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/82">Fixed a OIDC logout parameter</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/83">Audience congruency between OIDC and JWT</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/86">Wording and punctuation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/87">Fixed the HTML language attribute</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/89">Connectivity test mail</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/90">Updated Javascript dependencies</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/91">Trimmed translatable strings</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/92">LDAP model object refactoring</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/">Dynamic client registration fixes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/98">Deleting clients also delete linked attributes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/100">Admin token deletion</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/102">Display policy and TOS link on the user consents page</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/103">Fixed demo script messages</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/104">Display pre-authorized clients to users</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/106">User and group population command</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/109">More LDAP model object refactoring</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/111">Server-side search and pagination</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/112">Address field edition support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/113">Title field edition support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/114">Sub-menu and UX work</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/116">Organization edition support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/117">Avatar HTTP headers for caching</a></li>
</ul>
<h2><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h2>
<p><em>Nextcloud login via a single OpenID Connect 1.0 provider</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/220">Avoid avatar download when unnecessary</a></li>
</ul>
<h2><a href="https://github.com/azmeuk/flask-shell-ptpython">flask-shell-ptpython</a></h2>
<p><em>Ptpython shell for flask</em></p>
<ul>
<li><a href="https://github.com/jacquerie/flask-shell-ptpython/issues/18">(hopefully temporary) fork while the project is abandoned</a></li>
</ul>
<h2><a href="https://github.com/lepture/authlib">authlib</a></h2>
<p><em>Identity and Access management library for python</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/514">Useless code removal</a></li>
</ul>
<h2><a href="https://github.com/wtforms/wtforms">wtforms</a></h2>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/763">pre-commit update</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/764">python 3.11 support</a></li>
</ul>
<h2><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h2>
<p><em>Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/539">Unit tests fixes</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/540">Stop flask-babelx support</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/541">pre-commit update</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/542">python 3.11 support</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/546">1.1.0 release</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/549">Fixed unit tests with Flask-Babel 3</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/550">Ignore some flake8 warnings</a></li>
</ul>
<h2><a href="https://github.com/python-caldav/caldav">python-caldav</a></h2>
<p><em>Python CalDAV library</em></p>
<ul>
<li><a href="https://github.com/python-caldav/caldav/pull/242">3.11 support</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/pull/546">Bearer authentication support</a></li>
</ul>
<h2><a href="https://github.com/bamthomas/aioimaplib">aioimaplib</a></h2>
<p><em>Python asyncio IMAP4rev1 client library</em></p>
<ul>
<li><a href="https://github.com/bamthomas/aioimaplib/pull/86">Move from <code>setup.py</code> to <code>setup.cfg</code></a></li>
<li><a href="https://github.com/bamthomas/aioimaplib/pull/88">Pythonic assertions in the unit tests</a></li>
</ul>
<h2><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h2>
<p><em>Simple Autocomplete / typeahead component for Svelte</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/197">Menu stays closed when field is locked</a></li>
</ul>
<h2><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h2>
<p><em>Controls a slapd process in a pythonic way</em></p>
<ul>
<li><a href="https://github.com/python-ldap/python-slapd/pull/6">python 3.11 support</a></li>
<li><a href="https://github.com/python-ldap/python-slapd/pull/7">Increased the default database size</a></li>
</ul>
<h2><a href="http://supervisord.org/">supervisord</a></h2>
<p><em>A Process Control System written in Python</em></p>
<ul>
<li><a href="https://github.com/Supervisor/supervisor/pull/1583">Remove python3.3 case</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Packager son code python</title>
        <link href="https://blog-h4c5.vercel.app/docs/python/packaging-python" />
        <id>https://blog-h4c5.vercel.app/docs/python/packaging-python</id>
        <updated>2023-03-13T09:46:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Introduction à pyproject.toml et setuptools pour packager son code python.</p>
<hr/><a href="https://news.humancoders.com/t/python/items/20353-packager-son-code-python#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20353-packager-son-code-python">Packager son code python</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>hakim</name>
        </author>
    </entry>
    <entry>
        <title>Un graphe pour comprendre Tolkien ?</title>
        <link href="https://zestedesavoir.com/billets/4438/un-graphe-pour-comprendre-tolkien-1/" />
        <id>https://zestedesavoir.com/billets/4438/un-graphe-pour-comprendre-tolkien-1/</id>
        <updated>2023-02-13T13:27:12Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Ou comment utiliser la sciences des données et des graphes pour répondre à une problématique
            </div>
        </content>
        <author>
            <name>Solorme</name>
        </author>
    </entry>
    <entry>
        <title>IUT alternants : projet Django / Python à rendre le 12 février minuit au plus tard</title>
        <link href="https://www.olivierpons.fr/2023/01/03/lp-python-django/" />
        <id>https://www.olivierpons.fr/2023/01/03/lp-python-django/</id>
        <updated>2023-01-03T23:39:47Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>A rendre le <i>dimanche 12 février 2023 minuit au plus tard</i></h1>
<hr/>
<p>Projet <strong><em>individuel</em></strong></p>
<p><!-- 


<hr />


NB&nbsp;: excepté lorsqu'on se connecte, et se déconnecte, <strong><em>une seule page&nbsp;= aucun rechargement</em></strong>.

C'est totalement différent du projet que vous avez appris/fait en Php cette année. --></p>
<hr/>
<h2>Comment le rendre</h2>
<p>Faites un fichier README.txt et <a href="https://www.olivierpons.fr/exam/" rel="noopener noreferrer" style="color: blue;" target="_blank">déposez-le ici</a><br/>
Dans le fichier README.txt, précisez :</p>
<ul>
<li><b>le sujet choisi</b></li>
<li>l’adresse de votre site</li>
<li>un nom d’utilisateur</li>
<li>un mot de passe</li>
<li>(et plusieurs nom/mot de passe, s’il y a plusieurs niveaux de droits (administrateur/visiteur etc.))</li>
<li>si vous avez utilisé des librairies spécifiques que je vous ai autorisées, merci de le re-préciser</li>
</ul>
<hr/>
<h2>Sujet</h2>
<p>Ce que vous voulez <strong>tant que c’est dans le cadre de ce que l’on a vu</strong>. Vous avez tout le Web comme inspiration !<br/>
<strong>N’oubliez pas de me donner le nom et le mot de passe pour se connecter !</strong><br/>
<strong>Si vous gérez des profils différents (admin / user ou autre), donnez moi les noms et mots de passe de différents profils !</strong></p>
<hr/>
<h2>Fonctionnalités obligatoires</h2>
<ul>
<li>Nouveaux modèles</li>
<li>Nouvelles relations à mettre en oeuvre : ForeignKey, ManyToMany, OneToOne</li>
<li>Au moins un formulaire</li>
<li>Connexion + déconnexion (vu en cours)</li>
<li>Visualisation de tout dans l’interface d’administration</li>
<p><!--
 	

<li>Connexion + déconnexion (vu en cours)</li>


 	

<li>Effets jQuery sur les éléments</li>


 	

<li>Appels JSON : <strong>au moins deux appels en plus</strong> de ceux vus en cours</li>


-->
</p></ul>
<hr/>
<h2>Sujets possibles</h2>
<ol>
<li>Site de partage de photos</li>
<li>Site de cocktails (cf ci-dessus)</li>
<li>e-rated : site d’appréciations (selon des sujets, à définir)</li>
<li>Ask-a-question : site où l’on pose des questions sur des sujets divers, et des gens répondent</li>
<li>Write-a-book-together : site où l’on se connecte et où on peut écrire un livre à plusieurs</li>
<li>Wedding-couple-site : site où l’on uploade + partage des photos de mariage + livre de commandes</li>
<li>Playing-cards-collection : site où on scanne + échange des cartes (Magic the gathering)</li>
<li>Polls-and-surveys : site de création de sondages (= QCM, exemple très beau <a href="https://quipoquiz.com/fr/index" rel="noopener noreferrer" target="_blank">ici : quipoquiz</a>)</li>
<li>Poems-generator : faire un <a href="https://fr.wikipedia.org/wiki/Cadavre_exquis_(jeu)" rel="noopener noreferrer" target="_blank">cadavre exquis</a> qui génère des poèmes + possibilité pour les utilisateurs de les noter / d’ajouter des mots</li>
<li>The-future-of-post-it : faire un carnet de choses à faire pour les utilisateurs, qui envoie des mails de rappels de ces choses à des dates données</li>
<li>Gift-ideas : un site où l’on va faire des idées de cadeaux / suggérer des idées de cadeaux + les noter (les meilleurs ressortent en premier)</li>
<li>Le-bon-recoin : refaire le bon coin en plus simple</li>
<li>Suggest-crawlers : site de suggestions : on clique sur un mot, il en suggère plein d’autres avec + définitions / liens de sites pour chacuns</li>
<li>Tv-fans : site de présentations + notes d’émissions télé</li>
<li>Faire le jeu SokoBan vu en cours, avec la possibilité de login, enregistrement. Pour les appels JSON supplémentaires, lorsque l’utilisateur choisit un tableau, s’en souvenir (= AJAX) et lorsqu’il se reconnecte, le remettre directement. Puis enregistrer son score lorsqu’il a terminé un niveau + montrer les meilleurs scores.</li>
</ol>
<p>Pour les sujets qui suivent, ils sont possibles mais plutôt complexes et demandent plus d’investissement. Si vous êtes motivés, demandez-moi plus d’informations, je vous expliquerai les difficultés que vous allez rencontrer.</p>
<ol>
<li>Turn-by-turn : faire un jeu multijoueurs en tour par tour (jeu de cartes, de poker, ou de plateau etc)</li>
<li>Chat-with-someone : site de chat/discussion</li>
<li>A-maze-ing : site où l’on peut se ballader dans un labyrinthe et essayer d’en trouver la sortie</li>
</ol>
<h3>Sujet imposé si vous n’avez pas d’idée</h3>
<p>Cocktails : on se connecte, on a une liste d’éléments (récupérés en JSON) disponibles, on coche ceux qui nous intéressent, on valide, c’est envoyé, et le retour en JSON affiche les cocktails qu’il est possible de faire avec ce que l’on a coché.</p>
<hr/>
<h2>Ce que vous devez rendre</h2>
<p><strong>Idéalement</strong></p>
<ul>
<li>Une URL github / ou / gitlab.</li>
<li>Une URL vers un site Web (utilisez <a href="https://www.alwaysdata.com/" rel="noopener" target="_blank">Alwaysdata</a>, ou <a href="https://www.pythonanywhere.com/" rel="noopener" target="_blank">PythonAnywhere</a>, par exemple)</li>
</ul>
<p><strong>Si vous n’avez pas le choix</strong></p>
<p>Les fichiers source de votre projet</p>
<hr/>
<h2>Pour favoriser votre organisation</h2>
<p>Utilisez ce que l’on a vu en cours (Google boilerplate)</p>
<hr/>
<h2>Librairies autorisées</h2>
<ul>
<li><a href="https://getbootstrap.com/" rel="noopener noreferrer" target="_blank">Bootstrap</a> (utilisez éventuellement le boilerplate <a href="https://html5boilerplate.com/" rel="noopener noreferrer" target="_blank">ici vu ensemble</a>)</li>
<li><a href="https://jquery.com/" rel="noopener noreferrer" target="_blank">jQuery</a></li>
<li><a href="https://jqueryui.com/" rel="noopener noreferrer" target="_blank">jQueryUI</a></li>
<li><a href="https://github.com/CodeSeven/toastr" rel="noopener noreferrer" target="_blank">toastr</a></li>
<li><a href="https://jquerymobile.com/" rel="noopener noreferrer" target="_blank">jQuery Mobile</a></li>
<li><a href="https://developers.google.com/maps/documentation/javascript/?hl=fr" rel="noopener noreferrer" target="_blank">Google maps JavaScript API</a></li>
<li><a href="https://vegas.jaysalvat.com/" rel="noopener noreferrer" target="_blank">Vegas JS</a></li>
<li><a href="http://wiki.openstreetmap.org/wiki/OpenLayers" rel="noopener noreferrer" target="_blank">Openstreet maps JavaScript API</a></li>
<li><a href="https://github.com/select2/select2" rel="noopener noreferrer" target="_blank">Select 2 (select dynamique qui fait des appels AJAX)</a></li>
<li><a href="https://bulma.io/" rel="noopener noreferrer" target="_blank">bulma.io</a></li>
</ul>
<hr/>
<p><b>React autorisé</b></p>
<p><strong>Note pour ceux qui connaissent / font / du React : la librairie est autorisée</strong>, mais il me faut le code d’origine, et non pas le code minifié / de production.</p>
<hr/>
<h3>Interdiction d’utiliser une librairie JavaScript <strong>qui ne vienne pas des sites autorisés précédemment</strong></h3>
<hr/>
<h2>Retard</h2>
<h3>Après la date et heure limite</h3>
<p>Passé ce délai ce sera 1 pt par 2 heures de retard (mon robot qui analyse les mails prend en compte la date de réception du mail, tout est fait automatiquement).<br/>
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète.<br/>
Exemple : un point en moins si je le reçois un jour après à la minute près, soit date limite plus <code>00:01</code> minute.</p>
<p><strong>N’oubliez pas de me donner le nom et le mot de passe pour se connecter !</strong></p>
<hr/>
<h2>Copier-coller</h2>
<ul>
<li>Copie sur une autre personne (« je se savais pas comment implémenter telle ou telle fonctionnalité dont j’avais besoin pour aller plus loin, je l’ai copiée sur un autre ») :
<ul>
<li>si la personne est clairement nommée : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;</li>
<li>0 aux deux personnes sinon ;</li>
</ul>
</li>
<li>Si je m’aperçois que vous avez bêtement copié collé des sources Internet, je vous convoquerai pour vous demander de m’expliquer la fonctionnalité, et :
<ul>
<li>si vous ne savez pas m’expliquer le code alors 0 ;</li>
<li>si vous savez m’expliquer tout le code alors votre note totale sera divisée par vous + le nombre de contributeurs à ce projet, ce qui se rapprochera certainement de 0 aussi.</li>
</ul>
</li>
</ul>
<p><a href="https://www.olivierpons.fr/2018/03/12/exemple-cocktails/" rel="noopener noreferrer" target="_blank">Voici un exemple de ce que vous pouvez faire</a>, si vous choisissez le projet cocktails.</p>
<hr/>
<h2>PDFs</h2>
<p><a href="https://www.olivierpons.fr/download/python-django-2020-2021.pdf" rel="noopener noreferrer" target="_blank">Python Django</a></p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Nombres décimaux et Python</title>
        <link href="https://ascendances.wordpress.com/2022/12/31/nombres-decimaux-et-python/" />
        <id>https://ascendances.wordpress.com/2022/12/31/nombres-decimaux-et-python/</id>
        <updated>2022-12-31T20:44:06Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Python, comme de nombreux autres langages ainsi que des <a href="https://en.wikipedia.org/wiki/Floating-point_unit">implémentations matérielles</a>, suit la norme IEEE 754 pour manipuler les nombres à virgule (le type <code>float</code> en Python). Cette norme définit les tailles possibles de mémoire allouée pour contenir le nombre. La taille étant fixe, certains nombres ne sont pas représentables et la valeur enregistrée peut être légèrement erronée.</p>
<p>Cette situation n’est donc pas spécifique à Python. L’écart entre la valeur saisie et la valeur en mémoire est visible avec un interpréteur Python :</p>
<pre>$ python3 -q
&gt;&gt;&gt; 1.9999999999999943e+71
1.9999999999999942e+71
</pre>
<p>ou un calcul qui devrait valoir <code>0</code> si les mathématiques étaient une science exacte :</p>
<pre>$ python3 -q
&gt;&gt;&gt; 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
</pre>
<p>Ce type d’erreur ne se rencontre pas uniquement dans les domaines spatial ou scientifique. Par exemple, des calculs de TVA et TTC peuvent produire des erreurs visibles pour l’utilisateur.</p>
<p>Pour éviter ces erreurs, il est possible d’utiliser la bibliothèque <a href="https://docs.python.org/3/library/decimal.html">decimal</a> incluse dans la bibliothèque standard :</p>
<pre>$ python3 -q
&gt;&gt;&gt; from decimal import Decimal
&gt;&gt;&gt; decimal.Decimal('1.9999999999999943e+71')
Decimal('1.9999999999999943E+71')
&gt;&gt;&gt; Decimal(1) / Decimal(10) + \
... Decimal(1) / Decimal(10) + \
... Decimal(1) / Decimal(10) - \
... Decimal(3) / Decimal(10)
Decimal('0.0')
</pre>
<p>Un autre moyen est de faire des calculs en n’utilisant que des entiers et faire des conversions au dernier moment. Dans le cas de la TVA, cela signifie de ne travailler qu’en centimes et de ne convertir en euro que lors de l’affichage à l’utilisateur (avec l’arrondi adapté, limité à deux décimales).</p>
<h3>Références</h3>
<ul>
<li>pour plus de détails sur IEEE 754, la <a href="https://fr.wikipedia.org/wiki/IEEE_754">page wikipedia francophone</a></li>
<li>l’exemple de calcul provient de la documentation du module <a href="https://docs.python.org/3/library/decimal.html"><code>decimal</code></a></li>
<li>l’<a href="https://recher.wordpress.com/2022/11/30/medley-devenements-corporates/">article ayant inspiré</a> cet article</li>
</ul>
            </div>
        </content>
        <author>
            <name>ascendances</name>
        </author>
    </entry>
    <entry>
        <title>Dernières contributions à des logiciels libres par l&#39;équipe Yaal Coop (automne 2022)</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2022" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-automne-2022</id>
        <updated>2022-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/csernazs/pytest-httpserver">pytest-httpserver</a></h1>
<p><em>Serveur HTTP pour pytest</em></p>
<ul>
<li><a href="https://github.com/csernazs/pytest-httpserver/pull/185">Exemples de code pour la connection HTTPS</a></li>
<li><a href="https://github.com/csernazs/pytest-httpserver/pull/186">Fixtures de serveurs n'écoutant exclusivement qu'en IPV6 ou en IPV4</a></li>
<li><a href="https://github.com/csernazs/pytest-httpserver/pull/187">Implémentation de <code>BaseHTTPServer.__repr__</code></a></li>
</ul>
<h1><a href="https://github.com/samuelcolvin/dnserver">dnserver</a></h1>
<p><em>Serveur DNS simpliste pour le développement</em></p>
<ul>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/13">Exemples d'enregistrements SRV</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/15">Mise à jour à chaud des zones</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/16">Initialisation de la classe DNSServer sans zone</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/59">Support basique de WebFinger</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/60">Implémentation de l'enregistrement dynamique des clients</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/61">Support de Python 3.11</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/64">Corrections sur l'intégration continue de Gitlab</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/66">Instructions de configuration d'apparmor dans la documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/69">Divers réusinages</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/70">Correction du traîtement de <code>software_statement</code> du RFC7591</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/71">Génération dynamique des métadonnées OAuth2/OIDC du serveur</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/72">Correction de la désactivation du pré-consentement des clients</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/73">L'option de configuration <code>FROM_ADDR</code> devient facultative</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/74">L'option de configuration <code>JWT.ISS</code> devient facultative</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/75">Les utilisateurs peuvent choisir leur langage favori</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/76">Rajout d'un lien vers le dépôt dans la documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/77">Les utilisateurs peuvent choisir leur nom d'affichage</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/78">Mise à jour vers authlib 1.2</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/79">Implémentation du point d'accès de modification des clients RFC7592</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/80">Correction du bouton de suppression des groupes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/81">Correction du bug généré par des requêtes POST sur la page d'administration des clients</a></li>
</ul>
<h1><a href="https://github.com/zopefoundation/ZEO">ZEO</a></h1>
<p><em>Serveur de base de données pour ZODB</em></p>
<ul>
<li><a href="https://github.com/zopefoundation/ZEO/pull/215">Valeur de sortie à 1 si toutes les connexions serveur finissent en échec</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Plugin OpenID Connect pour nextcloud</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/191">Mise à jour vers OpenID-Connect-PHP 0.9.10</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/192">Documentation pour le paramètre <code>oidc_login_disable_registration</code></a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/193">Amélioration de la documentation dans le README</a></li>
</ul>
<h1><a href="https://github.com/lepture/authlib">authlib</a></h1>
<p><em>Bibliothèque python de gestion des identités et des accès</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/505">Implémentation de RFC7592 permettant la configuration dynamique de clients OpenID Connect</a></li>
<li><a href="https://github.com/lepture/authlib/pull/506">Support de Python 3.11</a></li>
<li><a href="https://github.com/lepture/authlib/pull/513">Suppression des références à une fonction inutilisée</a></li>
</ul>
<h1><a href="https://github.com/bamthomas/aioimaplib">aioimaplib</a></h1>
<p><em>Bibliothèque python asyncio IMAP4rev1</em></p>
<ul>
<li><a href="https://github.com/bamthomas/aioimaplib/pull/81">Tests unitaires avec pytest, tox et Github Actions</a></li>
</ul>
<h1><a href="https://msgpack.org">MessagePack</a></h1>
<p><em>Format de sérialisation binaire efficace (bibliothèque python)</em></p>
<ul>
<li><a href="https://github.com/msgpack/msgpack-python/pull/519">Nouvelles modifications suite à une revue de code</a></li>
</ul>
<h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Composant svelte de suggestion d'éléments dans une liste déroulante</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/185">Corrections d'avertissements d'accessibilité</a></li>
</ul>
<h1><a href="https://www.dnspython.org">dnspython</a></h1>
<p><em>outils DNS pour Python</em></p>
<ul>
<li>Nettoyage de code : <a href="https://github.com/rthalley/dnspython/pull/871">test</a> et <a href="https://github.com/rthalley/dnspython/pull/873">commentaire</a> obsolètes</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Last FOSS contributions from the Yaal Coop team (automn 2022)</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2022" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-automne-2022</id>
        <updated>2022-12-20T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/csernazs/pytest-httpserver">pytest-httpserver</a></h1>
<p><em>Http server for pytest to test http clients</em></p>
<ul>
<li><a href="https://github.com/csernazs/pytest-httpserver/pull/185">HTTPS client code samples</a></li>
<li><a href="https://github.com/csernazs/pytest-httpserver/pull/186">IPV6-only and IPV4-only server fixtures</a></li>
<li><a href="https://github.com/csernazs/pytest-httpserver/pull/187"><code>BaseHTTPServer.__repr__</code> implementation</a></li>
</ul>
<h1><a href="https://github.com/samuelcolvin/dnserver">dnserver</a></h1>
<p><em>Simple development DNS server</em></p>
<ul>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/13">Added a SRV record examples</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/15">Hot zones update</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/16">DNSServer initialization without zones</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/59">Basic WebFinger support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/60">Dynamic Client Registration support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/61">Python 3.11 support</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/64">Gitlab CI fixes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/66">Apparmor configuration instructions</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/69">Miscellaneous refactoring</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/70">Fixed RFC7591 <code>software_statement</code> claim handling</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/71">Dynamic OAuth2/OIDC metadata generation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/72">Fixed client preconsent disabling</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/73"><code>FROM_ADDR</code> configuration parameter is optional</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/74"><code>JWT.ISS</code> configuration parameter is optional</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/75">Users can chose their favorite language</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/76">Added a link to the repository in the documentation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/77">Users can choose their favourite display name</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/78">Upgrade to authlib 1.2</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/79">Implemented RFC7592 OAuth Client Registration Management</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/80">Fixed the group deletion button</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/81">Fixed a bug related to POST requests on the client administration pages</a></li>
</ul>
<h1><a href="https://github.com/zopefoundation/ZEO">ZEO</a></h1>
<p><em>ZODB Client-Server framework</em></p>
<ul>
<li><a href="https://github.com/zopefoundation/ZEO/pull/215">Exit value is 1 if all connections fail</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Nextcloud login via a single OpenID Connect 1.0 provider</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/191">Updated OpenID-Connect-PHP to 0.9.10</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/192"><code>oidc_login_disable_registration</code> parameter documentation</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/193">README documentation improvements</a></li>
</ul>
<h1><a href="https://github.com/lepture/authlib">authlib</a></h1>
<p><em>Identity and Access management library for python</em></p>
<ul>
<li><a href="https://github.com/lepture/authlib/pull/505">Implemented RFC7592 Dynamic Client Registration Management Protocol</a></li>
<li><a href="https://github.com/lepture/authlib/pull/506">Python 3.11 support</a></li>
<li><a href="https://github.com/lepture/authlib/pull/513">Unused method removal</a></li>
</ul>
<h1><a href="https://github.com/bamthomas/aioimaplib">aioimaplib</a></h1>
<p><em>Python asyncio IMAP4rev1 client library</em></p>
<ul>
<li><a href="https://github.com/bamthomas/aioimaplib/pull/81">Unit tests with pytest, tox and Github Actions</a></li>
</ul>
<h1><a href="https://msgpack.org">MessagePack</a></h1>
<p><em>Efficient binary serialization format (python implementation)</em></p>
<ul>
<li><a href="https://github.com/msgpack/msgpack-python/pull/519">New patches after code review</a></li>
</ul>
<h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Simple Autocomplete / typeahead component for Svelte</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/185">Fixed some accessibility warnings</a></li>
</ul>
<h1><a href="https://www.dnspython.org">dnspython</a></h1>
<p><em>DNS toolkit for Python</em></p>
<ul>
<li>Code cleaning: obsolete <a href="https://github.com/rthalley/dnspython/pull/871">test</a> and <a href="https://github.com/rthalley/dnspython/pull/873">comment</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>PyConFR 23 - La conférence francophone de Python est de retour en 2023</title>
        <link href="https://zestedesavoir.com/billets/4370/pyconfr-23-la-conference-francophone-de-python-est-de-retour-en-2023/" />
        <id>https://zestedesavoir.com/billets/4370/pyconfr-23-la-conference-francophone-de-python-est-de-retour-en-2023/</id>
        <updated>2022-12-12T19:15:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Rendez-vous du 16 au 19 février 2023
            </div>
        </content>
        <author>
            <name>Melcore</name>
        </author>
    </entry>
    <entry>
        <title>PyConFR 2023 - Conférences et ateliers autour de Python</title>
        <link href="https://www.helloasso.com/associations/afpy/evenements/pyconfr-2023" />
        <id>https://www.helloasso.com/associations/afpy/evenements/pyconfr-2023</id>
        <updated>2022-11-22T11:07:30Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Exposition organisé·e par l’Afpy l’Université Bordeaux-Talence 
Conférence annuelle des pythonistes francophones 🐍 🇫🇷
<a href="https://pycon.fr/2023/" rel="nofollow" target="_blank">https://pycon.fr/2023/</a>
Du jeudi 16 février au dimanche 19 février 2023</p>
<a href="https://news.humancoders.com/t/python/items/20212-pyconfr-2023-conferences-et-ateliers-autour-de-pyt"><img src="https://cdn.helloasso.com/img/photos/evenements/croppedimage-b05d4555f4d34c72b74caef2c884bb34.png"/></a><hr/><a href="https://news.humancoders.com/t/python/items/20212-pyconfr-2023-conferences-et-ateliers-autour-de-pyt#comments">Commentaires</a> <br/> L'article <a href="https://news.humancoders.com/t/python/items/20212-pyconfr-2023-conferences-et-ateliers-autour-de-pyt">PyConFR 2023 - Conférences et ateliers autour de Python</a> a été posté dans la catégorie <a href="https://news.humancoders.com/t/python">Python</a> de <a href="https://news.humancoders.com/">Human Coders News</a>
            </div>
        </content>
        <author>
            <name>Melcore</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Python 3.11</title>
        <link href="https://zestedesavoir.com/articles/4323/sortie-de-python-3-11/" />
        <id>https://zestedesavoir.com/articles/4323/sortie-de-python-3-11/</id>
        <updated>2022-10-26T12:29:46Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Il court il court, le serpent
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Un zeste de Python</title>
        <link href="https://zestedesavoir.com/tutoriels/2514/un-zeste-de-python/" />
        <id>https://zestedesavoir.com/tutoriels/2514/un-zeste-de-python/</id>
        <updated>2022-10-01T11:18:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Débuter avec Python
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Vérification de la syntaxe de certains fichiers de configuration</title>
        <link href="https://ascendances.wordpress.com/2022/09/28/verification-de-la-syntaxe-de-certains-fichiers-de-configuration/" />
        <id>https://ascendances.wordpress.com/2022/09/28/verification-de-la-syntaxe-de-certains-fichiers-de-configuration/</id>
        <updated>2022-09-28T17:56:21Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Certains logiciels fournissent aussi la possibilité de vérifier la syntaxe des fichiers de configuration qu’ils utilisent. Cela permet d’éviter des erreurs ou interruptions de service dûes à une erreur dans le fichier. Voici trois exemples :</p>
<h3>1. Apache</h3>
<p>Apache2 fournit <code>apachectl</code>. Si la syntaxe des sites actifs est correcte, la sortie sera :</p>
<pre class="wp-block-syntaxhighlighter-code"># apachectl -t
Syntax OK
</pre>
<p>Avec un fichier de configuration incorrect nommé <code>conte.conf</code> contenant</p>
<pre class="wp-block-syntaxhighlighter-code">&lt;VirtualHost a.oree.du.bois:80&gt;
    ServerName le.grand.mechant.loup.example
    CustomLog /il/etait/une/fois combined
    RencontreChaperonRouge on
&lt;/VirtualHost&gt;</pre>
<p>la sortie sera </p>
<pre class="wp-block-syntaxhighlighter-code"># apachectl -t
[Sun Sep 18 22:18:32.305781 2022] [core:error] [pid 14382:tid 139846731306112] (EAI 2)Name or service not known: AH00547: Could not resolve host name a.oree.du.bois -- ignoring!
AH00526: Syntax error on line 4 of /etc/apache2/sites-enabled/conte.conf:
Invalid command 'RencontreChaperonRouge', perhaps misspelled or defined by a module not included in the server configuration
Action '-t' failed.
The Apache error log may have more information.
</pre>
<p>Attention, les vérifications d’apachectl ne sont pas exhaustives et une erreur peut encore survenir lors du redémarrage du serveur Apache. Ici le chemin vers le fichier n’existe pas mais n’a pas été détecté. Si <code>apachectl -t</code> détecte une erreur, il y a un problème. S’il n’en détecte pas, il n’y a peut-être pas de problème.</p>
<p>(test réalisé avec Apache/2.4.38)</p>
<h3>2. OpenSSH</h3>
<p>La commande <code>sshd -t</code> exécutée avec des droits root permet de vérifier la validité de la configuration du serveur openSSH (le fichier <code>/etc/ssh/sshd_config</code> sous Debian).<br/>
Si le fichier est correct, alors rien n’est affiché et la valeur de sortie est 0.<br/>
Avec un fichier sshd_config commençant par :</p>
<pre class="wp-block-syntaxhighlighter-code">PetitPotDeBeurre on
Tartiflette off
</pre>
<p>La sortie sera :</p>
<pre class="wp-block-syntaxhighlighter-code"># sshd -t
[sudo] password for stephane: 
/etc/ssh/sshd_config: line 1: Bad configuration option: PetitPotDeBeurre
/etc/ssh/sshd_config: line 2: Bad configuration option: Tartiflette
/etc/ssh/sshd_config: terminating, 2 bad configuration options
</pre>
<p>avec une valeur de sortie de 255.</p>
<p>(test réalisé avec OpenSSH_7.9p1, OpenSSL 1.1.1d)</p>
<h3>3. Sudo</h3>
<p>Si une erreur est faite dans le fichier <code>/etc/sudoers</code> qui empêche sa relecture par l’exécutable <code>sudo</code>, il devient impossible d’utiliser la commande <code>sudo</code>. <code>visudo</code> permet d’éviter ce désagrément.<br/>
Supposons que l’utilisateur ait ajouté à la ligne 12,</p>
<pre>Hello           MereGrand</pre>
<p>puis enregistre le fichier :</p>
<pre class="wp-block-syntaxhighlighter-code">% sudo visudo
/etc/sudoers:12:25: erreur de syntaxe
Hello           MereGrand
^
Et maintenant ?
</pre>
<p>Lorsque le fichier est incorrect, trois choix sont possibles :</p>
<ul>
<li>remodifier le fichier</li>
<li>quitter sans enregistrer</li>
<li>quitter en enregistrant (une déception pourrait arriver peu de temps après)</li>
</ul>
<p>L’éditeur par défaut utilisé par <code>visudo</code> est <code>vi</code>. Cela est modifiable en paramétrant des variables d’environnement comme <code>$EDITOR</code>. (En réalité, c’est plus compliqué: il y a deux autres variables d’environnement possibles et deux variables de configuration de sudo permettent de modifier de comportement des éditeurs par défaut. <code>man sudo</code> si vous pensez que cette complexité a un intérêt dans votre cas.)</p>
<p>(testé avec visudo version 1.9.5p2, version de la grammaire de visudo : 48)</p>
<h3>Faim de loup, fin d’article</h3>
<p>Ces outils sont pratiques pour éviter de mettre un service en panne ou s’enfermer dehors. Ils sont complémentaires de vérificateur générique de syntaxe JSON, YAML, etc.</p>
            </div>
        </content>
        <author>
            <name>ascendances</name>
        </author>
    </entry>
    <entry>
        <title>Last FOSS contributions from the Yaal Coop team (summer 2022)</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2022" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-ete-2022</id>
        <updated>2022-09-21T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/">squeekboard</a></h1>
<p><em>An on-screen-keyboard input method for Wayland</em></p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/commit/b54922b021ad3c326a5de74dfba1e3ea3b7c32f5">French translation</a></li>
</ul>
<h1><a href="https://gitlab.gnome.org/World/Phosh/libcall-ui">libcall-ui</a></h1>
<p><em>User interface for Linux phone calls</em></p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/libcall-ui/-/commit/7cd3cfdd2ce1fe3e72614928f46c6376c226b1a7">French translation</a></li>
</ul>
<h1><a href="https://developer.mozilla.org/fr/">Mozilla Web Docs</a></h1>
<p><em>Documentation about web technologies, including CSS, HTML, and JavaScript</em></p>
<ul>
<li><a href="https://github.com/mdn/content/pull/16769">Add a Warning</a> about deprecated <a href="https://developer.mozilla.org/en-US/docs/Web/OpenSearch">OpenSearch</a> for Firefox add-ons</li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/54">Client-initiated logout</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/55">Online demo</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/56">Fixed too permissive scopes</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/57">Adding a dark theme</a></li>
</ul>
<h1><a href="https://python.org">Python</a></h1>
<ul>
<li>Documentation: <a href="https://github.com/python/cpython/pull/93574">replace domain names not managed by PSF</a> by python.org et domain names with .example Top Level Domain (cf. <a href="https://github.com/python/cpython/issues/93573">issue</a>) in the documentation</li>
</ul>
<h1><a href="https://github.com/python-caldav/caldav">python-caldav</a></h1>
<ul>
<li><a href="https://github.com/python-caldav/caldav/pull/193">Support for multiple authentication methods server headers</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/194">Tox configuration</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/195">Configured Github Actions</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/197">Pytest migration</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/198">Build the documentation with tox</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/199">Precommit installation</a></li>
</ul>
<h1>Debian Archive Kit (dak)</h1>
<p><em>Programs used to maintain the Debian project's archives</em></p>
<ul>
<li><a href="https://salsa.debian.org/ftp-team/dak/-/merge_requests/254">Fix E123 flakes8 errors</a>. E123 code means "closing bracket does not match indentation of opening bracket's line".</li>
</ul>
<h1>Python2 will disappear</h1>
<ul>
<li>Removal of a workaround for older releases than 2.6 in <a href="https://github.com/Pylons/webtest/pull/244">Webtest</a></li>
<li>Documentation: removal of an example based on python2 in <a href="https://github.com/nickstenning/honcho/pull/235">Honcho</a></li>
<li>Removal of python2.7 specific cases in <a href="https://github.com/pypa/setuptools/pull/3564">setuptools</a></li>
<li>Removal python2 support in <a href="https://github.com/msgpack/msgpack-python/pull/519">msgpack</a></li>
</ul>
<h1><a href="https://gitlab.gnome.org/GNOME/tracker-miners/">tracker-miners</a></h1>
<p><em>Data collectors for GNOME tracker</em></p>
<ul>
<li><a href="https://gitlab.gnome.org/GNOME/tracker-miners/-/merge_requests/395">Added CLI options for RSS feeds addition and deletion</a></li>
</ul>
<h1><a href="https://python-poetry.org/docs/">poetry</a></h1>
<p><em>Tool for dependency management and packaging in Python</em></p>
<ul>
<li><a href="https://github.com/python-poetry/poetry/pull/3995">Add a warning if credentials are written in lock file</a></li>
<li><a href="https://github.com/python-poetry/poetry-plugin-export/pull/93">Add private attribute to fit the implementation of the mocked class</a> (needed for previous patch)</li>
</ul>
<h1><a href="https://github.com/migraf/fhir-kindling">fhir-kindling</a></h1>
<p><em>FHIR resource and synthetic data set creation and management tool</em></p>
<ul>
<li><a href="https://github.com/migraf/fhir-kindling/pull/99">Bugfix for proxy support</a></li>
<li><a href="https://github.com/migraf/fhir-kindling/pull/105">Bugfix for custom headers support</a></li>
</ul>
<h1><a href="https://github.com/nazarewk/keyring_pass">keyring_pass</a></h1>
<p><em>Password Store (pass) backend for python's keyring</em></p>
<ul>
<li><a href="https://github.com/nazarewk/keyring_pass/pull/2">Documentation improvements</a></li>
<li><a href="https://github.com/nazarewk/keyring_pass/pull/6">Deprecation fixes</a></li>
</ul>
<h1><a href="https://github.com/samuelcolvin/dnserver">dnserver</a></h1>
<p><em>Simple development DNS server</em></p>
<ul>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/2">Implemented unit tests</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/9">The DNS proxy feature can be disabled</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/10">Added code samples in the README</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Nextcloud login via a single OpenID Connect 1.0 provider</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/186">Updated OpenID-Connect-PHP to 0.9.8</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/187">Fixed linter errors</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/releases/tag/v2.3.3">Released v2.3.3</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Dernières contributions à des logiciels libres par l&#39;équipe Yaal Coop (été 2022)</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2022" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-ete-2022</id>
        <updated>2022-09-21T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/">squeekboard</a></h1>
<p><em>Un clavier virtuel pour Wayland</em></p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/commit/b54922b021ad3c326a5de74dfba1e3ea3b7c32f5">Traduction française</a></li>
</ul>
<h1><a href="https://gitlab.gnome.org/World/Phosh/libcall-ui">libcall-ui</a></h1>
<p><em>Interface utilisateur pour les appels téléphoniques sous Linux</em></p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/libcall-ui/-/commit/7cd3cfdd2ce1fe3e72614928f46c6376c226b1a7">Traduction française</a></li>
</ul>
<h1><a href="https://developer.mozilla.org/fr/">Mozilla Web Docs</a></h1>
<p><em>Documentation sur les technologies du web, dont CSS, HTML et Javascript</em></p>
<ul>
<li><a href="https://github.com/mdn/content/pull/16769">Ajout d'une alerte</a> à propos de la fonctionnalité dépréciée <a href="https://developer.mozilla.org/en-US/docs/Web/OpenSearch">OpenSearch</a> pour les greffons Firefox.</li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/54">Déconnexions initiées par les clients</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/55">Instance de démo en ligne</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/56">Correction d'un bug où les scopes était trop permissifs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/57">Ajout d'un thème sombre</a></li>
</ul>
<h1><a href="https://python.org">Python</a></h1>
<ul>
<li>Documentation : <a href="https://github.com/python/cpython/pull/93574">remplacement de noms de domaine non contrôlés par la PSF</a> par python.org et des noms de domaines qui sont clairement des exemple (cf. <a href="https://github.com/python/cpython/issues/93573">signalement</a>) dans la documentation</li>
</ul>
<h1><a href="https://github.com/python-caldav/caldav">python-caldav</a></h1>
<ul>
<li><a href="https://github.com/python-caldav/caldav/pull/193">Support pour les serveurs supportant plusieurs méthodes d'authentification</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/194">Configuration tox</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/195">Configuration de l'intégration continue avec Github Actions</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/197">Migration vers pytest</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/198">Construction de la documentation avec tox</a></li>
<li><a href="https://github.com/python-caldav/caldav/pull/199">Installation de pre-commit</a></li>
</ul>
<h1>Debian Archive Kit (dak)</h1>
<p><em>Programmes utilisés pour maintenir les archives du projet Debian</em></p>
<ul>
<li><a href="https://salsa.debian.org/ftp-team/dak/-/merge_requests/254">Correction des erreurs flake8 E123</a>. Le code E123 concerne des parenthèses fermantes ne correspondant pas à l'indentation des parenthèses ouvrantes.</li>
</ul>
<h1>Python2 finira par disparaître</h1>
<ul>
<li>Suppression d'un contournement pour les version antérieures à 2.6 dans <a href="https://github.com/Pylons/webtest/pull/244">Webtest</a></li>
<li>Documentation : suppression d'un exemple basé sur python2 dans <a href="https://github.com/nickstenning/honcho/pull/235">Honcho</a></li>
<li>Suppression de cas spécifiques à python2.7 dans <a href="https://github.com/pypa/setuptools/pull/3564">setuptools</a></li>
<li>Suppression de python2 dans <a href="https://github.com/msgpack/msgpack-python/pull/519">msgpack</a></li>
</ul>
<h1><a href="https://gitlab.gnome.org/GNOME/tracker-miners/">tracker-miners</a></h1>
<p><em>Collecteurs de données pour GNOME Tracker</em></p>
<ul>
<li><a href="https://gitlab.gnome.org/GNOME/tracker-miners/-/merge_requests/395">Ajout d'options CLI pour l'ajout et la suppression de flux RSS</a></li>
</ul>
<h1><a href="https://python-poetry.org/docs/">poetry</a></h1>
<p><em>Outil pour la gestion des dépendances et des paquets en Python</em></p>
<ul>
<li><a href="https://github.com/python-poetry/poetry/pull/3995">Ajout d'une alerte si des identifiants sont écrits dans le fichier poetry.lock</a></li>
<li><a href="https://github.com/python-poetry/poetry-plugin-export/pull/93">Ajout d'un attribut privé pour correspondre à l'implémentation d'une classe fictive (mock)</a> (nécessaire pour le correctif précédent)</li>
</ul>
<h1><a href="https://github.com/migraf/fhir-kindling">fhir-kindling</a></h1>
<p><em>Brique de connexion à des serveurs de ressources FHIR</em></p>
<ul>
<li><a href="https://github.com/migraf/fhir-kindling/pull/99">Correctif pour le support des serveurs proxy</a></li>
<li><a href="https://github.com/migraf/fhir-kindling/pull/105">Correctif pour le support des entêtes personnalisées</a></li>
</ul>
<h1><a href="https://github.com/nazarewk/keyring_pass">keyring_pass</a></h1>
<p><em>Connecteur Password Store (pass) pour python-keyring</em></p>
<ul>
<li><a href="https://github.com/nazarewk/keyring_pass/pull/2">Améliorations de la documentation</a></li>
<li><a href="https://github.com/nazarewk/keyring_pass/pull/6">Correction de dépréciations</a></li>
</ul>
<h1><a href="https://github.com/samuelcolvin/dnserver">dnserver</a></h1>
<p><em>Serveur DNS simpliste pour le développement</em></p>
<ul>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/2">Tests unitaires</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/9">La fonctionnalité de proxy DNS est désactivable</a></li>
<li><a href="https://github.com/samuelcolvin/dnserver/pull/10">Ajout d'exemples dans le README</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Plugin OpenID Connect pour nextcloud</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/186">Mise à jours vers OpenID-Connect-PHP 0.9.8</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/187">Correction d'erreurs de mise en forme du code</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/releases/tag/v2.3.3">Publication de la version 2.3.3</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Purism Librem 5 software review : our list to Santa</title>
        <link href="https://yaal.coop/blog/en/purism-librem5-software-santas-list" />
        <id>https://yaal.coop/blog/en/purism-librem5-software-santas-list</id>
        <updated>2022-06-01T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>After several years of waiting, we just received our <a href="https://puri.sm/products/librem-5/">Librem 5 phone</a> from Purism.
The Librem 5 phone is a privacy-oriented phone which notable features are:</p>
<ul>
<li>it uses <a href="https://pureos.net">PureOS</a>, a GNU/Linux distribution based on Debian, instead of Android or iOS;</li>
<li>the interface is based on <a href="https://gnome.org">GNOME</a> with a few modifications;</li>
<li>it has kill switches to physically disable wifi, bluetooth, cellular data, camera and microphone.</li>
</ul>
<p>Running a Linux on a cellular phone enables new uses, especially for tech savvy, but it comes with its lot of drawbacks.
The main notable ones is that Linux phones is a brand new field, and a lot of apps are simply 'not ready'.
Either because their UI is not adaptive, because they have not been adapted to mobile user interactions (swiping and other gestures), or just because they have not been tested enough by users, so some actions feels convoluted.</p>
<p>FOSS developers do their best, and a whole lot of great work has been done so far.
However we are not yet at a point where Linux phones can be put in the hands of a larger audience.
With our fresh eyes of new Linux mobile users, we want to list here the main things that we felt were really missing to provide a good user experience (at least for our biased geeky use).
We focused on <a href="https://apps.gnome.org/">GNOME Core and Circle apps</a>, and mobile/Librem5 specific apps developed by Purism.
What we expect from a phone is to:</p>
<ul>
<li>place calls</li>
<li>receive and send SMS</li>
<li>receive and send emails</li>
<li>be used as an alarm clock</li>
<li>manage contacts</li>
<li>manage tasks</li>
<li>be used as a geolocation navigation device</li>
<li>browse the internet</li>
<li>play music</li>
<li>take photos</li>
<li>take notes</li>
<li>display documents</li>
<li>share internet connection</li>
<li>be used as a torchlight</li>
<li>discuss with people</li>
</ul>
<p>As patching has even more value than reporting, this list could be used by us (or you?) as a to-do list for some day if we get bored.</p>
<p>We have tested the phone running <a href="https://pureos.net/">PureOS byzantium</a>, and we updated all the apps through <a href="https://flathub.org">Flatpak</a> when possible so we could get the latest GNOME 42 fixes.</p>
<h1>Blockers</h1>
<p>In this category we put the issues we feel are very discouraging for a daily use.
This mainly concerns UX friction and stress, and missing or broken features.</p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/">Squeekboard</a> - <a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/issues/93">Alternate characters popovers</a>: We Europeans use a lot of diacritics, the keyboard should offer us a way easily write any common accentuated character.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues/">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/84">Translation have to be forced</a>: At first launch, the welcome panel asks the user for their language, but this action is uneffective and the system is displayed in English after that. This is easy to fix with a command-line, but surprising for a first-launch.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Clocks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/1">Alarms should ring even when the application is not launched</a>: If an alarm has been set, it should ring on time, no matter what. Having to launch the application to get the alarm ring is unexpected.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Clocks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/100">Alarms should wake the system up</a>: If an alarm has been set, it should ring on time, no matter what. Alarms should wake the system up if needed.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Clocks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/10">Custom alarm sound</a>: At the moment, the only alarm sound is the default one.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Clocks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/160">Interact with an alarm from the lock screen</a>: Currently it is needed to enter the PIN code before we can stop the alarms. When you wake up, this is harsh.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/">Squeekboard</a> - <a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/issues/282">Input indicator</a>: When a key is tapped, users should have a visual indication of which key is actually pressed.</li>
<li><a href="https://source.puri.sm/Librem5/linux">Librem5</a> - <a href="https://source.puri.sm/Librem5/linux/-/issues/387">Night light support</a>: GNOME provide a night light feature that reddish the screen automatically depending on the hour. It seems there are some kernel thing to do to enable this. Without this, watching to the screen at night just kill your eyes.</li>
<li><a href="https://gitlab.gnome.org/GNOME/calls/">Calls</a> - <a href="https://gitlab.gnome.org/GNOME/calls/-/issues/456">Alphabet side bar</a>: The application lacks an alphabet side bar to quickly jump to some letters in the contact list. With thousands of contacts this would become more than useful.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-contacts">Contacts</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/246">Alphabet side bar</a>: The application lacks an alphabet side bar to quickly jump to some letters in the contact list. With thousands of contacts this would become more than useful.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-todo/">To-Do</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-todo/-/issues/274">Adaptive UI</a>: The UI is not adaptive at the moment, so To-Do is not usable.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-weather/">Weather</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-weather/-/issues/236">Adaptive UI</a>: The application is not adapted to mobile UI.</li>
<li><a href="https://gitlab.gnome.org/GNOME/fractal/">Fractal</a> - <a href="https://gitlab.gnome.org/GNOME/fractal/-/issues/717">End-to-end encryption</a>: At Yaal Coop we encrypt our conversations, so E2EE in Fractal is a blocker to us.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Maps</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/264">Adaptive UI</a>: The side-menu is not usable on a Librem 5 at this point.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Maps</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/335">Navigation view</a>: The application can calculate itineraries, but do not provide anything to follow the itineraries. Is is not usable in a car yet.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Maps</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/2">Long-press to open the contextual menu</a>: Some actions are only accessible via right click on desktop, so on mobile they just cannot be done. A long press on the map should have the same effect as a right click.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-online-accounts/">Online Accounts</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-online-accounts/-/issues/1">CarDAV &amp; CalDAV provider support</a>: This would allow to plug any contact, calendar and todo list provider to the system.</li>
<li><a href="https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info">mobile-broadband-provider-info</a> - <a href="https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info/-/merge_requests/38">TeleCoop support</a>: This allows to use data with <a href="https://telecoop.fr/">TeleCoop</a>. The patch is applied but not yet deployed.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-software">Software</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1472">UI is sluggish</a>: When Flatpak in enabled, any actions takes decades to achieve, to the point that it is sometimes needed to restart the app.</li>
<li><a href="https://gitlab.com/kop316/vvmplayer">Voicemail</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/267">There is no working voicemail app at the moment</a>: Having the ability to easily listen to voicemails is a must-have on a 2022 phone.</li>
</ul>
<h1>Comfort</h1>
<p>In this category we put the issues that would improve our comfort.
This mainly concern mobile UX improvements.</p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/9">Automatic light and dark theme switch</a>: Along with the screen warmness adaptation, switching from a light to a dark theme when the night comes is a bliss for the eyes. This is achievable with GNOME Shell with the <a href="https://extensions.gnome.org/extension/2236/night-theme-switcher/">Night Theme Switcher</a> extension for instance.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/934">Swipe to open and close the menu</a>: As of today, the application menu and the top menu can only be opened by tapping. However swiping to open the menu feels more natural on mobile. This have been implemented but not yet deployed.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/397">Automatically unlock the keyring</a>: When opening a new session with a PIN, it is then asked a second time to unlock the GNOME keyring. This feels redundant.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/525">Hold the volume buttons to change volume</a>: Currently, we have to press the buttons multiple times in order to change the volume.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/265">Ask the encryption passphrase at first boot</a>: At first boot, a (default) passphrase is asked to decrypt the disk, in English, with a qwerty keyboard. It would be friendlier to not ask it a the first boot and let the user choose it.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/265">Disk decryption screen l10n</a>: The disk decryption screen is in English, with a qwerty keyboard, so it is not adapted to other languages.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/784">Keep the time displayed when the top menu is opened</a>: The time is hidden when the top menu is opened. Time is still an interesting information to display when the menu is opened, and without this the top bar appears strangely empty. This seems to be fixed but not yet deployed.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/783">Toggle geolocation from the top menu</a>: In the top menu there are button to toggle wifi or bluetooth, but not to toggle geolocation.</li>
</ul>
<h1>Sparkles</h1>
<p>In this category we put everything else that we met during our test, from nice-to-have features to slight mobile UX improvements:</p>
<ul>
<li><a href="https://source.puri.sm/Librem5/chatty/">Chatty</a> - <a href="https://source.puri.sm/Librem5/chatty/-/issues/698">Swipe to return to the message list</a>: When a message is displayed, there is an arrow button that allows to go back to the message list, but the more natural action on mobile would be to swipe left.</li>
<li><a href="https://gitlab.gnome.org/GNOME/geary/">Geary</a> - <a href="https://gitlab.gnome.org/GNOME/geary/-/issues/1377">Swipe to return to the message list</a>: When a message is displayed, there is an arrow button that allows to go back to the message list, but the more natural action on mobile would be to swipe left.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-calendar">Calendar</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/702">Swipe to navigate between weeks or months</a>: Swipe would be more adapted to mobile screens than the current arrows.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-calendar">Calendar</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/838">Selection visual indicator</a>: During a selection on touchscreen, users have no feedback until their finger is released.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-calendar">Calendar</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/670">Adaptive UI</a>: Calendar displays good enough on mobile, but some details are missing. For instance, the tooltips can be larger than the screen.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Clocks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/238">Analog watch widget</a>: Tapping multiple times on the screen to select hours and minutes is cumbersome. An analog watch widget could achieve the action in on two taps.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-disk-utility">Disks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-disk-utility/-/issues/251">Adaptive UI</a>: The encryption menu is not adaptive, but this is still usable.</li>
<li><a href="https://github.com/dialect-app/dialect/">Dialect</a> - <a href="https://github.com/dialect-app/dialect/issues/254">Slow performances at startup</a>: The applications takes several seconds to start.</li>
<li><a href="https://github.com/dialect-app/dialect/">Dialect</a> - <a href="https://github.com/dialect-app/dialect/issues/255">Cannot close the preferences dialog</a>: It has a close button on GNOME Shell, but not on phosh.</li>
<li><a href="https://github.com/dialect-app/dialect/">Dialect</a> - <a href="https://github.com/dialect-app/dialect/issues/211">Offline translations</a>: Because we are not always connected.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Maps</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/1">Offline maps</a>: To save mobile data, it would be better to pre-download maps and routes on a Wifi connection for instance.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-dictionary">Dictionary</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-dictionary/-/issues/15">Offline dictionary</a>: Currently, an internet connection is needed to use the app.</li>
<li><a href="https://gitlab.gnome.org/GNOME/evince/">Evince</a> - <a href="https://gitlab.gnome.org/GNOME/evince/-/issues/1256">Automatically switch to night mode</a>: Evince allows to manually invert the background color at night. This should be done automatically depending on the system dark mode.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps">Maps</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/452">Double-tap to zoom</a>: On desktop double-clicking zooms, as should do double-tapping on touchscreen.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard">Squeekboard</a> - <a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/merge_requests/552">Bépo support</a>: This one does only concerns a few nerds, but bépo (a French dvorak layout) support would be awesome.</li>
<li><a href="https://gitlab.gnome.org/GNOME/geary">Geary</a> - <a href="https://gitlab.gnome.org/GNOME/geary/-/issues/1196">Image banner is not adaptive</a>: The image display banner does not display well on mobile.</li>
<li><a href="https://gitlab.gnome.org/GNOME/epiphany">Web</a> - <a href="https://gitlab.gnome.org/GNOME/epiphany/-/issues/1801">Password banner is not adaptive</a>: The password banner does not display well on mobile.</li>
<li><a href="https://gitlab.gnome.org/World/deja-dup">Backups</a> - <a href="https://gitlab.gnome.org/World/deja-dup/-/issues/310">Adaptive UI</a>: The home screen does not display well on mobile.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/138">Mobile data traffic counter</a>: This would be a useful utility when data is limited.</li>
<li><a href="https://github.com/lakoliu/Furtherance">Furtherance</a> - <a href="https://github.com/lakoliu/Furtherance/issues/52">Home screen is not adaptive enough</a>: The French translation of the application provokes UX adaptivity issues.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-notes/">Notes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-notes/-/issues/134">Adaptive UI</a>: Notes is not yet adaptive.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-control-center">Settings</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/231#note_1469421">Bluetooth screen is not adaptive enough</a>: As usual, some French content makes the panel too large.</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Revue logicielle du Librem 5 de Purism</title>
        <link href="https://yaal.coop/blog/purism-librem5-software-santas-list" />
        <id>https://yaal.coop/blog/purism-librem5-software-santas-list</id>
        <updated>2022-06-01T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Après plusieurs années d'attente, nous venons de recevoir le <a href="https://puri.sm/products/librem-5/">Librem 5</a> que nous avions commandé chez Purism.
C'est un téléphone orienté vie-privée dont les fonctionnalités notables sont :</p>
<ul>
<li>l'utilisation de <a href="https://pureos.net">PureOS</a>, une distribution GNU/Linux basée sur Debian, à la place d'Android ou iOS ;</li>
<li>l'interface graphique est <a href="https://gnome.org">GNOME</a> avec quelques modifications ;</li>
<li>la présence de boutons permettant de physiquement éteindre le Wifi, le Bluetooth, les données mobiles, le microphone ou la caméra (c'est à dire couper l'arrivée électrique).</li>
</ul>
<p>Utiliser Linux sur un téléphone mobile ouvre à de nouveaux usages qui concernent surtout des personnes technophiles, mais cela vient aussi avec son lot d'inconvénients.
Les plus notables sont que les téléphones sous Linux sont quelque chose de nouveau, et les applications ne sont simplement pas prêtes : les interface ne sont adaptées aux écrans mobiles, les interactions pratiques sur un téléphone mobile (comme le glissement du pouce) ne sont pas utilisées, et plus généralement les applications n'ont pas encore été assez testées par des utilisateurs mobiles.</p>
<p>Les développeurs de logiciels libres font de leur mieux, et un sacré travail a déjà été fait.
Cependant nous ne sommes pas encore à un point où les téléphones sous Linux peuvent être mis entre toutes les mains.
Avec notre regard vierge (c'est la première fois que nous voyons un téléphone sous Linux), nous voulons lister ici ce que nous pensons qu'il manque à l'écosystème pour fournir un bonne expérience utilisateur (du moins pour notre usage biaisé de technophiles).</p>
<p>Nous nous sommes concentrés sur les applications <a href="https://apps.gnome.org/">GNOME Core et Circle</a>, ainsi que sur les applications mobiles développées par Purism.</p>
<p>Ce que nous attendons d'un téléphone est qu'il nous permette de :</p>
<ul>
<li>passer des appels</li>
<li>recevoir et envoyer des SMS</li>
<li>recevoir et envoyer des emails</li>
<li>être utilisé comme réveil</li>
<li>gérer ses contacts</li>
<li>gérer des listes de tâches</li>
<li>être utilisé comme un appareil de géolocalisation</li>
<li>naviguer sur internet</li>
<li>jouer de la musique</li>
<li>prendre des photos</li>
<li>prendre des notes</li>
<li>afficher des documents</li>
<li>partager sa connexion internet</li>
<li>être utilisé comme lampe-torche</li>
<li>discuter avec des gens</li>
</ul>
<p>Comme produire des correctifs a encore plus de valeur que rapporter des bugs, cette liste pourrait nous servir de liste de tâches à faire si nous (ou vous ?) nous ennuyons un jour.</p>
<p>Nous avons testé le téléphone sous <a href="https://pureos.net/">PureOS byzantium</a>, et mis à jour les applications grâce à <a href="https://flathub.org">Flatpak</a> quand c'était possible afin de bénéficier des avancées de GNOME 42.</p>
<h1>Bloquants</h1>
<p>Dans cette catégorie nous listons les problèmes qui nous découragent fortement pour une utilisation quotidienne.
Cela concerne principalement du stress et de la friction dans l'expérience utilisateur, ainsi que des fonctionnalités manquantes ou inutilisables.</p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/">Clavier virtuel</a> - <a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/issues/93">Infobulles pour les caractères accentués</a> : Le clavier devrait offrir un moyen simple d'écrire des caractères accentués.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues/">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/84">L'interface n'est pas traduite</a> : Au premier lancement la langue préférée de l'utilisateur est demandée, mais l'interface reste affichée en anglais par la suite. C'est assez simple à corriger à la main, mais c'est assez surprenant.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Horloges</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/1">Les réveils devraient sonner même quand l'application n'est pas lancée</a> : Une fois qu'un réveil est programmé, il devrait sonner quoi qu'il arrive, même si l'application a été fermée.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Horloges</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/100">Les réveils devraient sonner même quand le téléphone est en veille</a> : Une fois qu'un réveil est programmé, il devrait sonner quoi qu'il arrive, même si le téléphone est en veille.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Horloges</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/10">Sons de réveil personnalisés</a> : Pour le moment il n'y a pas de choix des sons à jouer.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Clocks</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/160">Interaction avec le réveil depuis l'écran de verrouillage</a> : À l'heure actuelle il faut déverrouiller le téléphone pour éteindre le réveil. Quand on vient d'ouvrir les yeux, c'est assez compliqué.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard/">Clavier virtuel</a> - <a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/issues/282">Indicateurs d'interaction</a> : Lorsqu'une lettre est pressée, on devrait avoir un indicateur visuel pour indiquer de quelle lettre il s'agissait.</li>
<li><a href="https://source.puri.sm/Librem5/linux">Librem5</a> - <a href="https://source.puri.sm/Librem5/linux/-/issues/387">Lumière nocturne</a> : GNOME a une fonctionnalité de lumière nocturne qui rougit l'écran automatiquement en fonction de l'heure. Il semblerait qu'il y a des choses à faire dans le noyau pour utiliser cette fonctionnalité avec le Librem5.</li>
<li><a href="https://gitlab.gnome.org/GNOME/calls/">Appels</a> - <a href="https://gitlab.gnome.org/GNOME/calls/-/issues/456">Barre latérale de navigation alphabétique</a> : L'application manque d'un outil pour rapidement sauter à une lettre donnée de l'alphabet, ce qui est très utile lorsqu'on a des centaines de contacts.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-contacts">Contacts</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/246">Barre latérale de navigation alphabétique</a> : L'application manque d'un outil pour rapidement sauter à une lettre donnée de l'alphabet, ce qui est très utile lorsqu'on a des centaines de contacts.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-todo/">Tâches</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-todo/-/issues/274">Interface mobile</a> : L'interface n'est pas adaptée aux mobiles, donc l'application est inutilisable pour le moment.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-weather/">Météo</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-weather/-/issues/236">Interface mobile</a> : L'application n'est pas tout à fait adaptée aux mobiles.</li>
<li><a href="https://gitlab.gnome.org/GNOME/fractal/">Fractal</a> - <a href="https://gitlab.gnome.org/GNOME/fractal/-/issues/717">Chiffrement de bout en bout</a> : À Yaal Coop nous chiffrons tous nos salons, donc le chiffrement de bout en bout est nécessaire pour que nous puissions utiliser Fractal.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Cartes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/264">Interface mobile</a> : Le menu latéral n'est pas adapté aux mobiles.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Cartes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/335">Navigation</a> : L'application peut calculer des itinéraires, mais ne fournit rien pour les suivre. On ne peut donc pas encore l'utiliser dans une voiture.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Cartes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/2">Appui long pour ouvrir le menu contextuel</a> : Certaines actions sont cachées derrière le menu contextuel sur bureau, qui s'ouvre avec un clic droit. Sur mobile on ne peut donc pas ouvrir ce menu. Un appui long devrait permettre d'ouvrir le menu.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-online-accounts/">Comptes en ligne</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-online-accounts/-/issues/1">Support des fournisseurs CarDAV &amp; CalDAV</a> : Cela permettrait de se brancher à n'importe quel fournisseur de contacts, agendas, et tâches.</li>
<li><a href="https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info">mobile-broadband-provider-info</a> - <a href="https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info/-/merge_requests/38">Suppport de l'opérateur TéléCoop</a> : Cela permet l'utilisation des données mobiles avec <a href="https://telecoop.fr/">TéléCoop</a>. Le correctif est appliqué, mais pas encore déployé.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-software">Logiciels</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1472">L'interface n'est pas réactive</a> : Lorsque les dépôts Flatpak sont actifs, chaque action prend une éternité à s'exécuter, au point qu'il faille de temps en temps redémarrer l'application.</li>
<li><a href="https://gitlab.com/kop316/vvmplayer">Messagerie vocale</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/267">Pas d'application fonctionnelle de messagerie vocale</a>: Pouvoir consulter ses messages (ou à défaut être averti qu'il en existe) nous semble indispensable pour un téléphone en 2022.</li>
</ul>
<h1>Confort</h1>
<p>Dans cette catégorie nous lisons ce qui améliorerait notre confort.
Cela concerne principalement les interfaces.</p>
<ul>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/9">Changement automatique des thèmes clairs et sombres</a> : En plus de l'adaptation de la rougeur de la luminosité, passer d'un thème clair à un thème sombre le soir est très reposant pour les yeux. C'est faisable avec GNOME Shell avec l'extension <a href="https://extensions.gnome.org/extension/2236/night-theme-switcher/">Night Theme Switcher</a> par exemple.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/merge_requests/934">Glisser pour ouvrir et fermer le menu</a> : Pour le moment les menus du haut et du bas ne s'ouvrent qu'en tapant, or glisser est plus naturel sur mobile. Le correctif est développé mais pas encore déployé.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/397">Dévérouiller automatiquement le trousseau</a> : Lorsqu'on déverouille une session, le mot de passe est demandé une seconde fois pour dévérouiller le trousseau de mots de passes.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/525">Garder les boutons appuyés pour changer le volume sonore</a> : Pour le moment il est nécessaire d'appuyer plusieurs fois sur les boutons de volume pour pouvoir le changer. Un appui long devrait permettre la même chose.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/265">Choix de la phrase de chiffrement au premier démarrage</a> : Au premier démarrage, une phrase de chiffrement par défaut est demandée à l'utilisateur, en anglais, avec un clavier qwerty. Il nous semblerait plus accessible de demander à l'utilisateur de choisir sa phrase de déchiffrement au premier démarrage, une fois qu'il a choisi sa langue et son clavier.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/265">Internationalisation de l'écran de déchiffrement du disque</a> : L'écran de déchiffrement du disque est en anglais, avec un clavier virtuel en qwerty.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/784">Garder l'horloge affichée lorsque le menu du haut est ouvert</a> : L'horloge est masquée lorsque le menu du haut est ouvert. Le correctif est développé mais pas encore déployé.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/phosh/">Phosh</a> - <a href="https://gitlab.gnome.org/World/Phosh/phosh/-/issues/783">Activer ou non la géolocalisation depuis le menu du haut</a> : Dans le menu du haut on peut activer ou désactiver le Wifi ou le Bluetooth, mais pas la géolocalisation.</li>
</ul>
<h1>Paillettes</h1>
<p>Dans cette catégorie nous listons toutes les autres choses que nous avons rencontrées, il s'agit surtout de petites améliorations d'interface et quelques fonctionnalités qui permettraient par exemple un usage hors-ligne.</p>
<ul>
<li><a href="https://source.puri.sm/Librem5/chatty/">SMS</a> - <a href="https://source.puri.sm/Librem5/chatty/-/issues/698">Glisser pour retourner à la liste des messages</a> : Lorsqu'un message est affiché, glisser vers la gauche devrait ramener à la liste des messages.</li>
<li><a href="https://gitlab.gnome.org/GNOME/geary/">Emails</a> - <a href="https://gitlab.gnome.org/GNOME/geary/-/issues/1377">Glisser pour retourne à la liste des messages</a> : Lorsqu'un email est affiché, glisser vers la gauche devrait ramener à la liste des messages.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-calendar">Agenda</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/702">Glisser pour naviguer entre les mois ou les semaines</a> : Glisser nous semble plus adapté aux interfaces mobiles que les flèches actuellement présentes.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-calendar">Agenda</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/838">Indicateur visuel de sélection</a> : Lorsque l'on sélectionne une période, on n'a aucun indicateur visuel de ce qui est sélectionné avant d'avoir terminé la sélection.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-calendar">Agenda</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/670">Interface mobile</a> : Agenda ne s'affiche pas trop mal sur mobile, mais certains détails manquent. Par exemple, les infobulles peuvent être plus larges que l'écran.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-clocks">Horloges</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-clocks/-/issues/238">Widget de montre analogique</a> : Taper à multiple reprises pour changer les minutes ou les heures n'est pas pratique. Afficher un cadran d'horloge analogique permettrait de faire la même chose en tapant seulement deux fois sur l'écran.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-disk-utility">Disques</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-disk-utility/-/issues/251">Interface mobile</a> : Le menu de chiffrement n'est pas adapté aux mobiles, mais l'application reste utilisable.</li>
<li><a href="https://github.com/dialect-app/dialect/">Traductions</a> - <a href="https://github.com/dialect-app/dialect/issues/254">Mauvaises performances au démarrage</a> : L'application met plusieurs secondes à se lancer.</li>
<li><a href="https://github.com/dialect-app/dialect/">Traductions</a> - <a href="https://github.com/dialect-app/dialect/issues/255">Impossible de fermer la fenêtre de préférences</a> : Il manque un bouton pour fermer la fenêtre.</li>
<li><a href="https://github.com/dialect-app/dialect/">Traductions</a> - <a href="https://github.com/dialect-app/dialect/issues/211">Traductions hors-ligne</a> : Parce que nous ne sommes pas toujours connectés.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps/">Cartes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/1">Cartes hors-ligne</a> : Pour économiser des données, il serait intéressant de pré-télécharger les cartes, sur une connexion Wifi par exemple.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-dictionary">Dictionnaire</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-dictionary/-/issues/15">Dictionaire hors ligne</a> : Pour le moment une connection internet est nécessaire pour les traductions.</li>
<li><a href="https://gitlab.gnome.org/GNOME/evince/">Evince</a> - <a href="https://gitlab.gnome.org/GNOME/evince/-/issues/1256">Passer automatiquement en mode nocturne</a> : Evince permet de manuellement inverser les couleurs. Il serait pratique que le système fasse ça automatiquement en fonction du mode nocturne.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-maps">Cartes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-maps/-/issues/452">Taper deux fois pour zoomer</a> : Sur bureau un double clic permet de zoomer. Taper deux fois sur la carte devrait le permettre aussi.</li>
<li><a href="https://gitlab.gnome.org/World/Phosh/squeekboard">Clavier virtuel</a> - <a href="https://gitlab.gnome.org/World/Phosh/squeekboard/-/merge_requests/552">Support de la disposition Bépo</a> : Cela concerne une niche, mais nous adorerions voir arriver le support de la disposition Bépo.</li>
<li><a href="https://gitlab.gnome.org/GNOME/geary">Mails</a> - <a href="https://gitlab.gnome.org/GNOME/geary/-/issues/1196">La bannière d'affichage des images ne s'adapte pas aux écrans mobiles</a> : La bannière d'affichage des images n'est pas adaptée aux écrans mobiles.</li>
<li><a href="https://gitlab.gnome.org/GNOME/epiphany">Navigateur Web</a> - <a href="https://gitlab.gnome.org/GNOME/epiphany/-/issues/1801">La bannière d'enregistrement des mots de passe ne s'adapte pas aux écrans mobiles</a> : La bannière d'enregistrement des mots de passe n'est pas adaptée aux écrans mobiles.</li>
<li><a href="https://gitlab.gnome.org/World/deja-dup">Sauvegardes</a> - <a href="https://gitlab.gnome.org/World/deja-dup/-/issues/310">Interface mobile</a> : L'écran d'accueil n'est pas adapté aux mobiles.</li>
<li><a href="https://source.puri.sm/Librem5/OS-issues">Librem5</a> - <a href="https://source.puri.sm/Librem5/OS-issues/-/issues/138">Compteur d'utilisation des données mobiles</a> : Cela s'avérerait pratique pour les gens qui ont souscrit à des forfaits mobiles aux données limitées.</li>
<li><a href="https://github.com/lakoliu/Furtherance">Furtherance</a> - <a href="https://github.com/lakoliu/Furtherance/issues/52">La page d'accueil n'est pas assez adaptées aux écrans mobiles</a> : La traduction française de l'application pose des soucis d'affichage sur mobile.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-notes/">Notes</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-notes/-/issues/134">Interface mobile</a> : Notes n'est utilisable que sur le bureau.</li>
<li><a href="https://gitlab.gnome.org/GNOME/gnome-control-center">Paramètres</a> - <a href="https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/231#note_1469421">La fenêtre Bluetooth n'est pas assez adaptée aux écrans mobiles</a> : Comme d'habitude, les traduction françaises des applications font déborder le contenu de l'écran.</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Dernières contributions à des logiciels libres par l&#39;équipe Yaal Coop (début 2022)</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-debut-2022" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-debut-2022</id>
        <updated>2022-05-11T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ces derniers mois nous avons principalement contribué à <a href="https://gitlab.com/yaal/canaille">canaille</a>, le serveur d'identité que nous développons,
ainsi que le menu d'autocomplétion <a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a> et le greffon
<a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a> qui permet à nextcloud de se connecter à des serveurs d'identité.</p>
<h1><a href="https://github.com/wtforms/wtforms">wtforms</a></h1>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/721">Les champs de date peuvent manipuler plusieurs formats de date différents</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/722">Fin du support de python 3.6</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/30">Délai d'expiration pour les liens d'invitation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/31">Les utilisateurs invités peuvent choisir leur identifiant</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/33">Correction au lancement de la démo sur debian</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/34">Le nom de famille est nécessaire à l'inscription pour les inetOrgPerson</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/35">Début de séparation de la partie LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/36">Orthographe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/37">Augmentation de la longueur maximale des identifiants des jetons d'accès</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/38">Les jetons d'accès sont des JWT</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/39">Correction graphique sur le menu administrateur</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/40">Correction d'une faute de frappe dans la configuration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/41">Correction d'une erreur sur les groupes dans les invitations</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/42">Correction de problèmes d'empaquetage</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/43">Correction d'une erreur sur les utilisateurs sans nom de famille</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/45">Dockerisation de la démo</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/46">Ajout d'une option pour désactiver la réinitialisation de mot de passe</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/47">Ajout d'une option pour désactiver l'édition de profil</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/48">Support d'authlib 1.0.0</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/49">Instructions pour la génération des catalogues de traduction</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/50">Documentation</a></li>
</ul>
<h1><a href="https://github.com/Pylons/webtest">webtest</a></h1>
<p><em>Bibliothèque de tests unitaires pour applications web</em></p>
<ul>
<li><a href="https://github.com/Pylons/webtest/pull/241">Fin du support pour python 3.6, début du support pour python 3.10</a></li>
<li><a href="https://github.com/Pylons/webtest/pull/242">Support des balises HTML 'input', de type 'file', avec l'attribut 'multiple'</a></li>
</ul>
<h1><a href="https://github.com/nextcloud/server">nextcloud</a></h1>
<p><em>Logiciel de partage et de synchronisation de fichiers</em></p>
<ul>
<li><a href="https://github.com/nextcloud/server/issues/31301">Rapport de bug sur les partages fédérés</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Plugin OpenID Connect pour nextcloud</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/150">Formattage du code</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/159">Authentification avec les jetons utilisateurs</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/160">Authentification par mot de passe sur les vieilles routes</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/161">De meilleurs messages d'erreur en cas de problème</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/165">Support des avatars</a></li>
</ul>
<h1><a href="https://github.com/ansible/ansible">ansible</a></h1>
<p><em>Outil d'automatisation des déploiements</em></p>
<ul>
<li><a href="https://github.com/ansible/ansible/pull/76378">Créations et suppressions de chaînes par le module iptables</a></li>
</ul>
<h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Composant svelte de suggestion d'éléments dans une liste déroulante</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/127">Arrêter de nettoyer les requêtes localement lorsqu'elle doivent être traîtées à distance</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/147">Paramètre maxItemsToShowInList pour la fonction searchFunc</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/156">Ajout de tests unitaires</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/157">Réparation du comportement async</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/158">Correction d'un bug lors du rechargement des pages sur le site de démo</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/162">Refonte graphique du site de démo</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/163/">Encarts d'en-tête et de pied du menu déroulant personalisables</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/164">Correction d'un bug à l'initialisation avec une valeur pour le champ de saisie</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/165/">Correction concernant l'affichage de la croix de nettoyage de la saisie</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/166">Nettoyage des tests</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/168">Réorganisation des items par glisser-déposer en mode sélection multiple</a></li>
</ul>
<h1><a href="https://github.com/migraf/fhir-kindling">fhir-kindling</a></h1>
<p><em>Brique de connexion à des serveurs de ressources FHIR</em></p>
<ul>
<li><a href="https://github.com/migraf/fhir-kindling/pull/51">Documentation de la classe QueryResponse</a></li>
<li><a href="https://github.com/migraf/fhir-kindling/pull/61">Suppression d'un print inutile</a></li>
<li><a href="https://github.com/migraf/fhir-kindling/pull/63">Correction d'un warning en python 3.10</a></li>
</ul>
<h1><a href="https://www.debian.org/">Debian</a></h1>
<ul>
<li>Coloration syntaxique de code source dans le manuel <a href="https://www.debian.org/doc/debian-policy/index.html">Debian Policy</a> : <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=999566">signalement incluant le .diff à appliquer</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Last FOSS contributions from the Yaal Coop team (winter 2022)</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-debut-2022" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-debut-2022</id>
        <updated>2022-05-11T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Those last months we mainly worked on <a href="https://gitlab.com/yaal/canaille">canaille</a>, our identity server,
as well as the autocompletion menu <a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a> and
<a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a> that allows nextcloud to connect to identity servers.</p>
<h1><a href="https://github.com/wtforms/wtforms">wtforms</a></h1>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/721">Date related field can handle several formats</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/722">Stop support python 3.6</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/30">invitations expire after 48h</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/31">Invited users can choose their uid</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/33">find slapadd and ldapadd binaries on debian 11</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/34">surname is required when the user is created or updated</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/35">start the separation of the ldap parts</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/36">Spellcheck a word in french translatio</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/37">AuthorizationCode and Token have a new id parameter</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/38">JWT access token</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/39">Fix: better consistency of admin dropdown menu</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/40">Fix: spellcheck configuration key</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/41">fix: groups are saved even when invited user does not have read permission on groups</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/42">Fixed some packaging issues</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/43">fix cn/dn when user has no given name</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/45">make demo entirely runnable with docker-compose</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/46">Added an option to disable password recovery</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/47">Added an option to disable self edition</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/48">authlib 1.0.0</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/49">Generate mo files</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/50">more documentation to help contributors</a></li>
</ul>
<h1><a href="https://github.com/Pylons/webtest">webtest</a></h1>
<p><em>Wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.</em></p>
<ul>
<li><a href="https://github.com/Pylons/webtest/pull/241">stop python3.6 support</a></li>
<li><a href="https://github.com/Pylons/webtest/pull/242">Support for multiple file input</a></li>
</ul>
<h1><a href="https://github.com/nextcloud/server">nextcloud</a></h1>
<p><em>Nextcloud server, a safe home for all your data</em></p>
<ul>
<li><a href="https://github.com/nextcloud/server/issues/31301">Bug report: Accept/reject remote share action from "pending shares" view does not work</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Nextcloud login via a single OpenID Connect 1.0 provider</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/150">Use php-cs-fixer to format the code style</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/159">webdav Basic auth: login with user token</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/160">webdav endpoint v1 BasicAuthentication</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/161">BasicAuth: Raise an exception when the token is null or invalid</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/165">Update user avatars on login</a></li>
</ul>
<h1><a href="https://github.com/ansible/ansible">ansible</a></h1>
<p><em>simple IT automation platform</em></p>
<ul>
<li><a href="https://github.com/ansible/ansible/pull/76378">iptables: chains creation and deletion</a></li>
</ul>
<h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Simple Autocomplete / typeahead component for Svelte</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/127">skip client side input text filtering when request are done serverside</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/147">Pass maxItemsToShowInList to searchFunc</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/156">Unit tests</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/157">Fixed async behavior</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/158">user HTML anchors to keep the demo tabs on reloading</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/162">demo: use bulma messages</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/163/">Added dropdown header and footer slots</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/164">Initialization with the 'text' parameter</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/165/">Fixed multiple selection clear cross</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/166">Cleaned up directories</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/168">multiple selection reordering with drag and drop</a></li>
</ul>
<h1><a href="https://github.com/migraf/fhir-kindling">fhir-kindling</a></h1>
<p><em>FHIR resource and synthetic data set creation and management tool</em></p>
<ul>
<li><a href="https://github.com/migraf/fhir-kindling/pull/51">Document QueryResponse</a></li>
<li><a href="https://github.com/migraf/fhir-kindling/pull/61">removed a loud 'print'</a></li>
<li><a href="https://github.com/migraf/fhir-kindling/pull/63">Fixed a python warning</a></li>
</ul>
<h1><a href="https://www.debian.org/">Debian</a></h1>
<ul>
<li><a href="https://www.debian.org/doc/debian-policy/index.html">Debian Policy</a> syntax highlighting : <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=999566">bug report indication which patch to apply</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Les bases de numpy et matplotlib</title>
        <link href="https://zestedesavoir.com/tutoriels/4139/les-bases-de-numpy-et-matplotlib/" />
        <id>https://zestedesavoir.com/tutoriels/4139/les-bases-de-numpy-et-matplotlib/</id>
        <updated>2022-04-15T18:04:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Une introduction à numpy et matplotlib
            </div>
        </content>
        <author>
            <name>Gavroche</name>
        </author>
    </entry>
    <entry>
        <title>Visite aux JDLL 2022</title>
        <link href="https://yaal.coop/blog/jdll-de-lyon" />
        <id>https://yaal.coop/blog/jdll-de-lyon</id>
        <updated>2022-04-10T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Les 2 et 3 avril 2022, plusieurs associé·es de Yaal Coop étaient présents aux 23ièmes <a href="https://www.jdll.org/">Journées du Logiciel Libre</a> qui se déroulaient à Lyon. C'était l'occasion d'approfondir des sujets qui nous intéressaient, de faire quelques découvertes ainsi que de rencontrer des acteur·ices du Libre en personne.</p>
<p>Comme nous construisons un service d'hébergement nommé <a href="https://nubla.fr/">nubla</a>, assister aux présentations sur le collectif des <a href="https://www.chatons.org/">CHATONS</a> (Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires) et sur <a href="https://zourit.net/">zourit</a> ont été un moyen pour nous de confirmer (ou d'infirmer) nos choix sur le fonctionnement du service. Découvrir cette communauté donne du coeur à l'ouvrage !</p>
<p>Cela fait aussi plaisir de constater l'intérêt pour le mouvement coopératif, comme ce fut le cas lors des discussions animées de la session d'échange "Gouvernance du libre/Gouvernance des coopératives : quels points communs ?". Tout un programme... Qui nous conforte dans notre choix de <a href="https://yaal.coop/blog/de-yaal-a-yaal-coop">transformer Yaal en SCIC</a> fin 2020. Un choix loin d'être unique comme l'a encore démontrée cette discussion organisée par d'autres coopératives du numérique : <a href="https://hashbang.fr/">Hashbang</a>, <a href="https://tadaa.fr/">Tadaa</a> et <a href="https://www.probesys.com/">Probesys</a>.</p>
<p>D'un point de vue moins politique (quoi que...) à Yaal Coop nous avons un usage quotidien de claviers plus ou moins originaux (TypeMatrix, Truly Ergonomic, ErgoDox) et, pour certains, de personnalisations de disposition de clavier <a href="https://bepo.fr">bépo</a>. De fait, la présentation sur la fabrication personnalisée de clavier et sur la disposition récente tentant d'avoir une disposition agréable pour écrire en français, en anglais et pour programmer - <a href="https://ergol.org/">ergoL</a> -, ont piqué notre curiosité.</p>
<p><img alt="Tellement de type de claviers dans la zone des associations !" src="https://yaal.coop/media/blog/articles/jdll-2022-collection-de-claviers.webp" title="Tellement de type de claviers dans la zone des associations !"/></p>
<p>Cette conférence était l'occasion de parler avec des passionnés mais aussi celle de recroiser et discuter avec des personnes déjà rencontrées lors d'autres conférences (en l'occurence <a href="https://www.debconf.org/">DebConf</a> et <a href="https://www.pycon.fr">PyconFr</a>).</p>
<p>Le village associatif en particulier a été pour nous un lieu d'échanges, notamment avec Framasoft sur les avantages et les différences des formats coopératifs et associatifs.</p>
<p>Du coup, encore merci à tous les organisateurs et présentatrices, et vivement la prochaine ?</p>
            </div>
        </content>
        <author>
            <name>Stéphane Blondon &lt;stephane@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Supprimer les plus vieux fichiers d’un dossier tant qu’on dépasse une certaine taille</title>
        <link href="https://www.olivierpons.fr/2022/02/28/supprimer-les-plus-vieux-fichiers-dun-dossier-tant-quon-depasse-une-certaine-taille/" />
        <id>https://www.olivierpons.fr/2022/02/28/supprimer-les-plus-vieux-fichiers-dun-dossier-tant-quon-depasse-une-certaine-taille/</id>
        <updated>2022-02-28T22:33:49Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <hr/>
<h1>Exemples de lancement du script</h1>
<p><strong>Notez qu’il faut lancer en utilisant « <code>source</code>« </strong></p>
<ul>
<li>Supprimer les plus vieux fichiers du dossier <em>courant (<code>./</code>)</em> tant qu’il prend plus de 96Mo :<br/>
<code>source ./clean_custom.sh --path ./ -l 9600000</code></li>
<li>Supprimer les plus vieux fichiers du dossier temporaire (<code>/tmp/</code>) tant qu’il prend plus de 2Go :<br/>
<code>source ./clean_custom.sh --path /tmp/ -l 2000000000</code></li>
</ul>
<hr/>
<h1>Code du script</h1>
<pre style="font-size: 70%; line-height: normal;">#!/usr/bin/env bash                                                              
PATH_TO_CLEAN=                                                                   
NUMBER_FILES_TO_DELETE_EACH_LOOP=1                                               
SIZE_LIMIT=2000000000                                                            
                                                                                 
# ----------------------------------------------------------------------------   
# usage:                                                                         
usage()                                                                          
{                                                                                
    echo "Clean directory: while size of a dir &gt; limit, oldest files first."
    echo "Usage: ${filename} [-p|--path path] [-s|--max-size size] | [-h]"
    echo "    -p|--path: path to clean"            
    echo "    -l|--limit: max size for the folder (must be &gt; 0)"
    echo "    -h|--help this help"                 
}                                                                                
                                                                                 
# ----------------------------------------------------------------------------   
# handling arguments:                                                            
args=("$@")                                                            
filename=$(basename -- "$0" | sed 's/\(.*\)\..*/\1/')        
while [ "$1" != "" ]; do                                     
    case $1 in                                               
        -p | --path ) shift              
                      # stop if path doesn't exist:
                      if [ ! -d "$1" ]; then
                          echo "Path not found: '$1'"
                          usage
                          return 1
                      fi
                      PATH_TO_CLEAN=$1
                      ;;
        -l | --limit ) shift             
                       SIZE_LIMIT=$(echo $1 | bc)
                       if [ $SIZE_LIMIT -le 0 ]
                       then
                           usage
                           return 1
                       fi
                       ;;
        -h | --help ) usage              
                      return
                      ;;
        * ) usage                        
            return 1 
    esac                                                     
    shift                                                    
done                                                                             
[ -z "$PATH_TO_CLEAN" ] &amp;&amp; echo "Path empty" &amp;&amp; usage &amp;&amp; return 1
echo "Cleanin dir: '$PATH_TO_CLEAN', size limit=$SIZE_LIMIT" 
# ----------------------------------------------------------------------------   
# handling arguments:                                                            
while [ 1 ]                                                                      
do                                                                               
    s=$(du -sb $PATH_TO_CLEAN | cut -f1 | bc)                
    if [ $s -gt $SIZE_LIMIT ]                                
    then                                                     
        find $PATH_TO_CLEAN -type f -printf '%T+ %p\n' | \
            sort -nr | \
            tail -$NUMBER_FILES_TO_DELETE_EACH_LOOP | \
            cut -d' ' -f 2- | \
            xargs -I {} rm -f {}
    else                                                     
        break                            
    fi                                                                                                                                                                                                                                                      
done                                                                             
return 0</pre>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Retour d&#39;expérience concernant l&#39;usage d&#39;AlpineLinux comme conteneur</title>
        <link href="https://yaal.coop/blog/retour-d-experience-sur-alpine-linux-comme-conteneur" />
        <id>https://yaal.coop/blog/retour-d-experience-sur-alpine-linux-comme-conteneur</id>
        <updated>2022-02-14T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>AlpineLinux est une distribution souvent utilisée pour des conteneurs (lxc/lxd, Docker, etc.) car la taille des images d'AlpineLinux est minuscule (seulement 6 Mo !).
C'est un avantage réel, surtout si on a beaucoup de conteneurs. Si cette performance est remarquable, il est cependant nécessaire de prendre en compte l'ensemble des choix réalisés par la distribution.
Sur le <a href="https://www.alpinelinux.org/">site web</a>, il est clairement indiqué « Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox. ». Voyons quelles contraintes cela apporte :</p>
<h1>Les performances de musl</h1>
<p>AlpineLinux a fait le choix de musl comme bibliothèque C, contrairement à la plupart des distributions Linux qui utilisent la libc GNU. Il peut y avoir des problèmes de compilation ou d'exécution de logiciel qui ont été testées avec la glibc et pas avec musl mais nous n'avons jamais rencontré ce problème.</p>
<p>À l'exécution, musl est plus <a href="https://andygrove.io/2020/05/why-musl-extremely-slow/">lente</a> que la glibc. Par exemple, une compilation de cpython est <a href="https://lists.alpinelinux.org/~alpine/users/%3C6df8863e77b970b466dbfc9a3a5c2bcec3199f48.camel%40aquilenet.fr%3E">deux fois plus lente</a> qu'avec la glibc. C'est un problème connu des mainteneurs qui pourrait être résolu dans le futur en changeant d'allocateur mémoire. <a href="https://github.com/microsoft/mimalloc#performance">Mimalloc</a> semble être une bonne piste à l'avenir, mais pour l'instant, il faut vivre avec ce niveau de performance.</p>
<h1>L'environnement espace utilisateur</h1>
<h2>busybox</h2>
<p>AlpineLinux utilise <a href="https://www.busybox.net/">busybox</a> pour les outils Unix de base. Busybox est un projet éprouvé et utilisé depuis de nombreuses années dans l'embarqué.</p>
<p>Ce choix permet de minimiser la taille des outils embarqués par Alpine.</p>
<p>Mais, si le développement de script shell est réalisé sur un système disposant des outils GNU, il est possible qu'il y ait des erreurs lors de son exécution sur un système Alpine car le comportement n'est pas exactement le même : par exemple, il peut manquer des paramètres à certains outils (en particulier lorsque ce sont des extensions GNU à la norme Unix). Dans ce cas, il faut modifier le code ou installer un paquet pour embarquer l'outil GNU que l'on souhaite.</p>
<h2>systemd</h2>
<p>AlpineLinux utilise les scripts de démarrage classique Unix (dans <code>/etc/init.d/</code>) et non systemd. Selon les besoins et préférences de chacun, cela peut être une qualité ou un défaut.</p>
<h1>Les mises-à-jour</h1>
<p>Mettre à jour une version mineure d'alpine à l'autre (par exemple de 3.14 à 3.15) est très vite réalisé en quelques minutes. Comparé à la migration d'une version stable de Debian à la suivante, c'est étonnant et confortable puiqu'il n'y a pas de messages bloquants affichant les Changelog de changement incompatible ou des différences de fichiers de configuration entre la version du maitenant et celle du système en cours. L'inconvénient étant que les services peuvent être non fonctionnels ensuite...</p>
<p>Ce comportement n'est pas forcément un problème si l'usage est celui de conteneurs Docker qui sont supprimés et reconstruits à chaque modification. Dans le cas d'un usage classique avec des mises-à-jour, ça l'est beaucoup plus. L'usage d'instantanés (snapshot) peut permettre de limiter le problème : une fois la mise-à-jour faite, si des problèmes sont présents, il faut restaurer l'instantané fait avant la mise-à-jour puis chercher quel est le problème sur la version mise-à-jour.</p>
<h1>Conclusion</h1>
<p>Ces différents défauts ne sont pas forcément rédhibitoires selon l'usage fait d'AlpineLinux (par exemple pour des environnements docker locaux jetables). Il semble cependant important de les prendre en compte et se demander s'ils sont bloquants ou non avant de décider d'utiliser AlpineLinux selon l'usage prévu.</p>
<p>Après avoir utilisé AlpineLinux pour nos conteneurs lxc, nous avons conclu que l'utilisation de Debian était plus adapté à nos besoins dans ce cadre. Les prochains conteneurs seront donc basé sur Debian et les anciens migrés au fur et à mesure.</p>
            </div>
        </content>
        <author>
            <name>Stéphane Blondon &lt;stephane@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Hello Debian en Brainfuck</title>
        <link href="https://ascendances.wordpress.com/2022/02/08/hello-debian-en-brainfuck/" />
        <id>https://ascendances.wordpress.com/2022/02/08/hello-debian-en-brainfuck/</id>
        <updated>2022-02-08T19:50:43Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><a href="https://screenshots.debian.net/">screenshots.debian.net</a> est un service qui permet d’afficher des captures d’écran de logiciels. C’est assez pratique pour se faire une idée d’une interface par exemple. Une capture d’écran montrait déjà l’interpréteur Brainfuck <tt>beef</tt> affichant un classique<br/>
<code>Hello Word!</code>. Mais on peut aussi personnaliser en affichant un<br/>
<code>Hello Debian!</code> :</p>
<h3><img alt="Utilisation de beef" class="alignnone size-full wp-image-2828" height="146" src="https://ascendances.wordpress.com/wp-content/uploads/2022/02/beef.png" width="501"/></h3>
<h3>Brainfuck</h3>
<p>Brainfuck est un langage dont l’intérêt principal est d’être difficilement compréhensible par un humain. Pas la peine de s’étendre sur ses spécificités, <a href="https://fr.wikipedia.org/wiki/Brainfuck">wikipedia</a> le fait très bien. Il ressemble à une machine de Turing: le programme déplace un curseur dans un tableau et modifie les valeurs contenues dans les cellules du tableau.<br/>
Voici une version commentée du programme utilisé (le début est quasi-identique au <code>hello world</code> fourni sur la page wikipedia puisqu’on veut écrire la même chose) :</p>
<pre>++++++++++          affecte 10 à la case 0
[                   boucle initialisant des valeurs au tableau 
   &gt;                avance à la case 1 
   +++++++          affecte 7 à la case 1
   &gt;                avance à la case 2
   ++++++++++       affecte 10 à la case 2 
   &gt;                avance à la case 3
   +++              affecte 3 à la case 3
   &gt;                avance à la case 4
   +                affecte 1 à la case 4
   &gt;                avance à la case 5
   +++++++++++      affecte 11 à la case 5
   &lt;&lt;&lt;&lt;&lt;            retourne à la case 0
   -                enlève 1 à la case 0
]                   jusqu'à ce que la case 0 soit = à 0
</pre>
<p>La boucle initialise le tableau en 10 itérations et son état est alors :</p>
<table>
<tbody>
<tr>
<td>Case</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>Valeur</td>
<td>0</td>
<td>70</td>
<td>100</td>
<td>30</td>
<td>10</td>
<td>110</td>
</tr>
</tbody>
</table>
<p>Suite du programme :</p>
<pre>&gt;++                 ajoute 2 à la case 1 (70 plus 2 = 72)
.                   imprime le caractère 'H' (72)
&gt;+                  ajoute 1 à la case 2 (100 plus 1 = 101)
.                   imprime le caractère 'e' (101)
+++++++             ajoute 7 à la case 2 (101 plus 7 = 108)
.                   imprime le caractère 'l'  (108)
.                   imprime le caractère 'l'  (108)
+++                 ajoute 3 à la case 2 (108 plus 3 = 111)
.                   imprime le caractère 'o' (111)
&gt;++                 ajoute 2 à la case 3 (30 plus 2 = 32)
.                   imprime le caractère ' '(espace) (32)

&lt;&lt;&lt;                 revient à la case 0
++                  ajoute 2 à la case 0 (0 plus 2 = 2)
[                   une boucle
   &gt;                avance à la case 1 
   --               enlève 4 à la case 1 (72 moins 4 = 68)
   &gt;                avance à la case 2
   -----            enlève 10 à la case 2 (111 moins 10 = 101)
   &lt;&lt;               retourne à la case 0
   -                enlève 1 à la case 0
]                   jusqu'à ce que la case 0 soit = à 0

&gt;                   va case 1
.                   affiche 'D'
&gt;                   va case 2
.                   affiche 'e'
---                 enlève 3 à la case 2 (101 moins 3 = 98)
.                   affiche 'b'
&gt;&gt;&gt;                 va case 5
-----               enlève 5 à la case 5
.                   affiche 'i'
&lt;&lt;&lt;                 va case 2
-                   enlève 1 à la case 2
.                   affiche 'a'
&gt;&gt;&gt;                 va case 5
+++++               ajoute 5 à la case 5
.                   affiche 'n'
&lt;&lt;                  va à la case 3
+                   ajoute 1 à la case 3
.                   affiche un point d'exclamation

&gt;                   va à la case 4
.                   imprime le caractère 'nouvelle ligne' (10)

</pre>
<h3>screenshots.debian.net</h3>
<p>Une capture de l’exécution du programme est disponible pour les interpréteurs <a href="https://screenshots.debian.net/package/beef">beef</a> et <a href="https://screenshots.debian.net/package/hsbrainfuck">hsbrainfuck</a> sur screenshot.debian.net.<br/>
Les images disponibles sur screenshots.debian.net sont aussi réutilisées par le service packages.debian.org (par exemple <a href="https://packages.debian.org/bullseye/beef">packages.debian.org</a>) et par certains gestionnaires de paquets.<br/>
Si vous avez envie d’ajouter des captures d’écran à des paquets qui n’en auraient pas (les plus courants sont déjà faits), sachez que l’affichage n’est pas direct car il y a une validation manuelle des images envoyées. Le délai reste limité à quelques jours (voire à la journée).</p>
            </div>
        </content>
        <author>
            <name>ascendances</name>
        </author>
    </entry>
    <entry>
        <title>Django scripting : « AppRegistryNotReady: Apps aren’t loaded yet » solution</title>
        <link href="https://www.olivierpons.fr/2022/01/26/django-scripting-appregistrynotready-apps-arent-loaded-yet-solution-2/" />
        <id>https://www.olivierpons.fr/2022/01/26/django-scripting-appregistrynotready-apps-arent-loaded-yet-solution-2/</id>
        <updated>2022-01-26T11:23:02Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Si vous voulez faire un script simple qui veut importer <em>votre application construite sur le framework Django</em>, vous ferez sûrement ce code :</p>
<pre>import django
from app.models import MyModel</pre>
<p>Vous aurez sûrement cette erreur : <code>django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet</code>.</p>
<p>Pas de panique !<br/>
La solution est de lancer <code>setup()</code> de votre application avant les imports, comme suit :</p>
<pre>import django

if __name__ == '__main__':
    django.setup()
    # import AFTER setup
    from app.models import MyModel
    # je peux maintenant utiliser MyModel!!</pre>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Dernières contributions à des logiciels libres par l&#39;équipe Yaal Coop (fin 2021)</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-fin-2021" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-fin-2021</id>
        <updated>2021-12-16T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/yiisoft/yii2-authclient">yii2-authclient</a></h1>
<p><em>Brique de connexion OpenID Connect, notamment utilisée par <a href="https://www.humhub.com/">humhub</a></em></p>
<ul>
<li><a href="https://github.com/yiisoft/yii2-authclient/pull/334">Correctif sur la lecture du champ « aud » des ID tokens</a></li>
<li><a href="https://github.com/yiisoft/yii2-authclient/pull/333">Correctif concernant l'attribut « nonce » dans l'identification</a></li>
</ul>
<h1><a href="https://github.com/mstilkerich/rcmcarddav">rcmcarddav</a></h1>
<p><em>Greffon de synchronisation des contacts CardDAV pour l'interface web de gestion des mails <a href="https://roundcube.net/">Roundcube</a></em></p>
<ul>
<li><a href="https://github.com/mstilkerich/rcmcarddav/pull/355">Traduction française</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/8">Implémentation d'une commande 'check' qui vérifie la validité du fichier de configuration</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/9">Fonctionnalité de choix des audiences pour les tokens</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/10">Correction d'une erreur sur les droits d'introspection des tokens</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/11">Fonctionnalité de pré-autorisations des clients</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/12">La commande 'check' vérifie les permissions de l'utilisateur LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/13">Les consentements sont mis à jours lorsqu'un 'scope' OpenID Connect plus large est demandé par une application</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/14">Résolution d'un bug lorsque les groupes contiennent des membres invalides</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/15">Fonctionnalité de thèmes personnalisés</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/16">Options de configuration pour paramétrer la journalisation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/18">Liens d'invitation</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/19">Amélioration du nom de l'expéditeur dans les emails sortants</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/20">Refonte du système de permissions</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/21">Échappement des caractères spéciaux</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/23">Option permettant de désactiver l'utilisation d'OpenID Connect</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/24">Canaille reste utilisable si aucun serveur SMTP n'est configuré</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/25">Meilleures suggestions du champ d'identification</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/26">Configuration d'autres attributs pour identifier les objets du LDAP</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/27">Gestion des attributs jpegPhoto</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/28">Variabilisation du contenu des jetons JWT</a></li>
</ul>
<h1><a href="https://github.com/wtforms/wtforms">wtforms</a></h1>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/708">Corrections d'erreurs mineures de style</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/709">Mise à jour des dépendances de l'environnement de documentation</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/710">Découpage d'un gros fichier en plusieurs petits</a></li>
<li><a href="https://github.com/wtforms/wtforms/releases/tag/3.0.0">Publication de la version 3.0.0</a></li>
</ul>
<h1><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h1>
<p><em>Intégration de WTForms dans Flask</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/484">Ménage des fonctionnalités dépréciées</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.0.0">Publication de la version 1.0.0</a></li>
</ul>
<h1><a href="https://github.com/pallets/secure-cookie">secure-cookie</a></h1>
<p>La bibliothèque secure-cookie devrait être utilisée dans Flask à l'avenir.</p>
<ul>
<li><a href="https://github.com/pallets/secure-cookie/pull/66">Création automatique des répertoires de session</a></li>
</ul>
<h1><a href="https://gitlab.alpinelinux.org/alpine/aports/">aports</a></h1>
<p><em>Paquets de la distribution Alpine Linux</em></p>
<ul>
<li><a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/27041">Création du paquet py3-flask-themer</a></li>
<li><a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/27255">Mise à jour du paquet py3-flask-wtf</a></li>
<li><a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/27256">Mise à jour du paquet py3-wtforms</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/sheraf">sheraf</a></h1>
<p><em>Surcouche objet à ZODB</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/22">Meilleur affichage en console des attributs de collection</a></li>
</ul>
<h1><a href="https://github.com/jumbojett/OpenID-Connect-PHP">OpenID-Connect-PHP</a></h1>
<p><em>Bibliothèque OpenID Connect en PHP</em></p>
<ul>
<li><a href="https://github.com/jumbojett/OpenID-Connect-PHP/pull/276">Correction d'un bug dans la fonction <code>verifyJWTclaims</code></a></li>
<li><a href="https://github.com/jumbojett/OpenID-Connect-PHP/releases/tag/v0.9.3">Publication de la version 0.9.3</a></li>
<li><a href="https://github.com/jumbojett/OpenID-Connect-PHP/releases/tag/v0.9.4">Publication de la version 0.9.4</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Plugin OpenID Connect pour nextcloud</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/123">Support des jeton non JWT pour l'authentification WebDAV</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/136">Support de l'authentification DAV par mot de passe</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/137">Mise-à-jour d'OpenID-Connect-PHP en version 0.9.4</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/141">Mise-à-jour d'OpenID-Connect-PHP en version 0.9.5</a></li>
</ul>
<h1><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h1>
<p><em>Interface pythonique pour contrôler un serveur OpenLDAP</em></p>
<ul>
<li><a href="https://github.com/python-ldap/python-slapd/pull/4">Support de la commande ldapsearch</a></li>
<li><a href="https://github.com/python-ldap/python-slapd/pull/5">Le DN racine a les autorisations pour ajouter des schemas</a></li>
</ul>
<h1><a href="https://pygments.org/">Pygments</a></h1>
<p><em>Bibliothèque Python de coloration syntaxique</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/1946">Mise-à-jour du lexeur debian/control</a></li>
</ul>
<h1><a href="https://www.debian.org/">Debian</a></h1>
<ul>
<li>Mise-à-jour cosmétique des <a href="https://salsa.debian.org/ddp-team/release-notes/-/merge_requests/125">notes de publication</a>
et du <a href="https://salsa.debian.org/installer-team/installation-guide/-/merge_requests/16">guide d'installation</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Last FOSS contributions from the Yaal Coop team (fall 2021)</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-fin-2021" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-fin-2021</id>
        <updated>2021-12-16T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/yiisoft/yii2-authclient">yii2-authclient</a></h1>
<p><em>Yii 2 authclient extension</em></p>
<ul>
<li><a href="https://github.com/yiisoft/yii2-authclient/pull/334">OIDC: 'aud' claims can be arrays</a></li>
<li><a href="https://github.com/yiisoft/yii2-authclient/pull/333">Use nonce from the authentication request</a></li>
</ul>
<h1><a href="https://github.com/mstilkerich/rcmcarddav">rcmcarddav</a></h1>
<p><em>CardDAV plugin for RoundCube Webmailer</em></p>
<ul>
<li><a href="https://github.com/mstilkerich/rcmcarddav/pull/355">French translations</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/8">configuration check command</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/9">tokens can have multiple audiences</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/10">fixed introspection access rights</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/11">Implemented client pre-authorization</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/12">'check' command check ldap permissions</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/13">Updated consents when a larger scope is required</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/14">Fix bug on groups with non-existent members</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/15">use flask-themer to allow theme customization</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/16">Logging is configurable</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/18">Invitation links</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/19">Use the 'NAME' configuration parameter in the email sender name</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/20">Permissions overhaul</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/21">Escape filters</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/23">Option to not use OIDC</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/24">Disabled invitation and password reset when no smtp server has been configured</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/25">Login placeholder depends on the USER_FILTER configuration attribute</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/26">Added configuration options to tune object IDs</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/27">jpegPhoto management</a></li>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/28">customize jwt claims with format string in config file</a></li>
</ul>
<h1><a href="https://github.com/wtforms/wtforms">wtforms</a></h1>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/708">Fixed some style errors</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/709">updated docs dependencies</a></li>
<li><a href="https://github.com/wtforms/wtforms/pull/710">Field files split</a></li>
<li><a href="https://github.com/wtforms/wtforms/releases/tag/3.0.0">Released version 3.0.0</a></li>
</ul>
<h1><a href="https://github.com/wtforms/flask-wtf">flask-wtf</a></h1>
<p><em>Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.</em></p>
<ul>
<li><a href="https://github.com/wtforms/flask-wtf/pull/484">1.0 version deprecations removal</a></li>
<li><a href="https://github.com/wtforms/flask-wtf/releases/tag/v1.0.0">Released version 1.0.0</a></li>
</ul>
<h1><a href="https://github.com/pallets/secure-cookie">secure-cookie</a></h1>
<p><em>Secure cookies and sessions for WSGI</em></p>
<ul>
<li><a href="https://github.com/pallets/secure-cookie/pull/66">FilesystemSessionStore create directories if they don't exist</a></li>
</ul>
<h1><a href="https://gitlab.alpinelinux.org/alpine/aports/">aports</a></h1>
<p><em>Alpine packages build scripts</em></p>
<ul>
<li><a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/27041">py3-flask-themer package creation</a></li>
<li><a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/27255">py3-flask-wtf package update</a></li>
<li><a href="https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/27256">py3-wtforms package update</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/sheraf">sheraf</a></h1>
<p><em>A versatile ZODB abstraction layer</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/22">collections: better repr</a></li>
</ul>
<h1><a href="https://github.com/jumbojett/OpenID-Connect-PHP">OpenID-Connect-PHP</a></h1>
<p><em>Minimalist OpenID Connect client</em></p>
<ul>
<li><a href="https://github.com/jumbojett/OpenID-Connect-PHP/pull/276"><code>verifyJWTclaims</code>: fixed an exception when <code>$accessToken</code> is null</a></li>
<li><a href="https://github.com/jumbojett/OpenID-Connect-PHP/releases/tag/v0.9.3">Released version 0.9.3</a></li>
<li><a href="https://github.com/jumbojett/OpenID-Connect-PHP/releases/tag/v0.9.4">Released version 0.9.4</a></li>
</ul>
<h1><a href="https://github.com/pulsejet/nextcloud-oidc-login">nextcloud-oidc-login</a></h1>
<p><em>Nextcloud login via a single OpenID Connect 1.0 provider</em></p>
<ul>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/123">Allow WebDAV authentication with non JWT tokens</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/136">DAV Password authentication</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/137">Upgraded OpenID-Connect-PHP to version 0.9.4</a></li>
<li><a href="https://github.com/pulsejet/nextcloud-oidc-login/pull/141">Bumped to OpenID-Connect-PHP 0.9.5</a></li>
</ul>
<h1><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h1>
<p><em>Controls a slapd process in a pythonic way</em></p>
<ul>
<li><a href="https://github.com/python-ldap/python-slapd/pull/4">ldapsearch command</a></li>
<li><a href="https://github.com/python-ldap/python-slapd/pull/5">rootdn can add schemas</a></li>
</ul>
<h1><a href="https://pygments.org/">Pygments</a></h1>
<p><em>Pygments is a generic syntax highlighter written in Python</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/1946">Update debian control</a></li>
</ul>
<h1><a href="https://www.debian.org/">Debian</a></h1>
<ul>
<li><a href="https://salsa.debian.org/ddp-team/release-notes/-/merge_requests/125">Publication notes</a>
and <a href="https://salsa.debian.org/installer-team/installation-guide/-/merge_requests/16">installation guide</a> updates</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Un disque chiffré et partitionné avec Ubuntu</title>
        <link href="https://yaal.coop/blog/un-disque-chiffre-et-partitionne-avec-ubuntu" />
        <id>https://yaal.coop/blog/un-disque-chiffre-et-partitionne-avec-ubuntu</id>
        <updated>2021-10-25T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Ça y est, c'est décidé, vous avez une nouvelle machine, ou bien vous voulez repartir sur des bases propres et vous aimeriez <strong>chiffrer</strong> votre disque pour protéger vos données.</p>
<p>Dans votre fougue, vous vous dites qu'il serait également intéressant de séparer l'OS de vos données perso, avoir un /home sur une autre partition car vous savez que cela présente pas mal d'avantages : réinstaller ou changer de système d'exploitation sans perdre vos données, partager ces données entre plusieurs systèmes, les récupérer plus simplement en cas d'incident... <strong>Partitionner</strong> est une très bonne idée.</p>
<p>Actuellement, il est facile de chiffrer un disque en faisant une nouvelle installation d'Ubuntu 21.04, il est également facile de partitionner son disque avec une nouvelle installation d'Ubuntu 21.04. L'installeur est assez bon pour faire ces deux choses, mais il reste limité. Si vous voulez faire les deux en même temps à l'installation sur une machine, il va falloir faire ça à la main.</p>
<p>Pas de panique, vous êtes au bon endroit, cet article va vous donner les étapes à suivre pour installer <strong>Ubuntu 21.04</strong> (mais également beaucoup de versions <strong>précédentes</strong> et probablement beaucoup de <strong>futures versions</strong>) en ayant des partitions, notamment votre /home, sur un disque chiffré.</p>
<h1>Backup de vos données</h1>
<p>Tout d'abord, vous voulez protéger tout ce qui fait de votre ordinateur quelque chose d'unique. Vous sauriez le trouver parmi d'autres et il sait vous reconnaître. Vous avez vos habitudes avec lui et il en sait pas mal sur vous, vous aimeriez le retrouver tel quel.</p>
<p>Bref, il faut <strong>sauvegarder</strong> vos fichiers personnels, vos identités, vos configurations particulières, noter vos applications préférées...</p>
<h2>Fichiers</h2>
<p>Rien de très surprenant ici, votre dossier <code>/home</code> est probablement un bon endroit pour commencer.</p>
<p>Faites un <strong>backup</strong> de tout ce que vous voulez garder quelque part, comme un ssd, une clé usb, ou sur un Nextcloud de chez <a href="https://nubla.io">Nubla</a> ☁️ par exemple, un super service de cloud hébergé par une <a href="https://yaal.coop">petite coopérative Bordelaise sympathique</a>.</p>
<p>Mais vous faites probablement déjà tout ça, faire des sauvegardes régulières ou bien synchroniser vos fichiers important quelque part, n'est-ce pas ? Bien sûr que oui, car comme tout le monde, vous êtes prudent et intelligent. Personne ne serait assez étourdi pour ne pas faire de sauvegarde, évidemment.</p>
<h2>Applications</h2>
<p>Cette partie dépend de votre façon préférée d'installer des applications. Avec apt, snap, Ubuntu Software Center ? Probablement un peu de tout...</p>
<h3>Paquets apt</h3>
<p>Vous pouvez utiliser cette commande :</p>
<div class="highlight"><pre><span></span><code><span class="n">comm</span><span class="w"> </span><span class="o">-</span><span class="mi">23</span><span class="w"> </span><span class="o">&lt;</span><span class="p">(</span><span class="n">apt</span><span class="o">-</span><span class="n">mark</span><span class="w"> </span><span class="n">showmanual</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">sort</span><span class="w"> </span><span class="o">-</span><span class="n">u</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;</span><span class="p">(</span><span class="n">gzip</span><span class="w"> </span><span class="o">-</span><span class="n">dc</span><span class="w"> </span><span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="nb">log</span><span class="o">/</span><span class="n">installer</span><span class="o">/</span><span class="n">initial</span><span class="o">-</span><span class="n">status</span><span class="o">.</span><span class="n">gz</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">sed</span><span class="w"> </span><span class="o">-</span><span class="n">n</span><span class="w"> </span><span class="s1">'s/^Package: //p'</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">sort</span><span class="w"> </span><span class="o">-</span><span class="n">u</span><span class="p">)</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">apps_backup</span><span class="o">.</span><span class="n">txt</span>
</code></pre></div>
<p>pour générer une liste des paquets qui ont été manuellement installés et les enregistrer sur un fichier <code>apps_backup.txt</code>. Ce n'est qu'une seule manière de faire, vous pouvez modifier cette commande pour avoir une liste plus exhaustive si vous préférez valider que tout va bien.</p>
<p><code>apt-mark showmanual</code> donne les paquets apt installés manuellement ainsi que ceux installés avec l'installeur d'Ubuntu. On peut récupérer cette liste de paquets d'installation initiale dans le log <code>/var/log/installer/initial-status.gz</code>. On compare ces deux listes et on ne garde que ce qui reste de la première avec la commande comm pour l'inscrire dans un fichier <code>apps_backup.txt</code>.</p>
<p>Vous trouverez beaucoup de commandes similaires sur les internets, trouvez celle qui vous conviendra le mieux, celle-ci a bien fonctionné pour moi. Évidemment, vous devez garder ce fichier en lieu sûr.</p>
<h3>snap</h3>
<p>Il est possible que dans certains cas vous ayez eu besoin de snap pour installer certains logiciels. vous pouvez les lister avec :</p>
<div class="highlight"><pre><span></span><code>snap list
</code></pre></div>
<p>Malheureusement, je n'ai pas trouvé de de moyens de lister ceux qui ont été installés manuellement, mais vous serez capable de faire le tri, retenez ceux que vous utilisez.</p>
<h3>Ubuntu Software</h3>
<p>Vous pouvez aussi lancer Ubuntu Software Center et afficher la liste des applications installées.</p>
<h2>Fichiers de configuration</h2>
<p>En tant que personne maline, vous n'avez pas besoin de lire cette partie, car vos fichiers de configuration perso, vos "dotfiles", sont déjà copiés quelque part, probablement partagés et peut-être même versionnés.</p>
<p>Alors, je vais seulement lister les quelques fichiers importants que j'utilise, juste pour mon futur moi, lui éviter la jobardise et atteindre, qui sait, cet état d'intelligente prudence :</p>
<ul>
<li>les fichiers .profile ou .bash_profile ou .bash_login... pour les sessions</li>
<li>.bashrc, .zshrc et/ou autres pour le shell</li>
<li>les aliases</li>
<li>.gitconfig et/ou .hgrc pour la config de vos VCS</li>
<li>la config de votre prompt</li>
<li>.vimrc pour la config de vim</li>
<li>...</li>
</ul>
<h2>Identités</h2>
<p>À moins que vous ayez envie de recommencer depuis zéro avec vos identifiants, comptes, etc., vous devriez garder précieusement vos configurations ssh (où toutes vos connections serveur sont paramétrées), votre base de donnée pass ou keepass (ou tout autre manager de mot de passe local), vos paires de clés publiques ET privées SSH, GPG et autres..., vos vaults et probablement beaucoup d'autres choses dont comme moi, vous vous souviendrez malheureusement trop tard. Je ne vous le souhaite pas, soyez organisé...</p>
<h1>Installation d'Ubuntu</h1>
<p>Vous êtes détendu, frais, tout est en sécurité, alors vous êtes prêt.</p>
<h2>Lancer Ubuntu</h2>
<p>Vous avez besoin d'une clé usb bootable, d'au moins 4gb, que vous pouvez créer avec le paquet usb-creator-gtk (ou usb-creator-kde).</p>
<p>Il faudra ensuite redémarrer votre ordinateur avec la clé usb branchée. Pour booter sur la clé, vous devez lancer le menu de boot normalement en pressant "<em>F12</em>", mais cela peut changer selon les machines. En général, un message sera affiché sur l'écran de lancement pour vous indiquer quelle touche il faudra enfoncer (pour moi, il s'agissait d'appuyer frénétiquement sur "<em>Enter</em>" jusqu'à ce qu'un son soit émis...).</p>
<p>Une fois qu'Ubuntu a été lancé depuis la clé, l'installeur se lance automatiquement. Vous pouvez cliquer sur "<strong>Try Ubuntu</strong>" ou bien aller un peu en avant dans l'installation de votre Ubuntu ce qui pourra peut-être vous faciliter la suite.</p>
<p>À titre d'exemple, de mon côté j'ai choisi l'anglais comme langue d'installation et donc la langue d'Ubuntu (principalement pour trouver plus simplement des ressources sur le web) puis sur l'écran suivant, j'ai sélectionné la disposition correspondant à mon clavier (ce qui facilite nos prochaines manipulations). J'ai ensuite quitté l'installateur sans aller plus loin pour pouvoir paramétrer le disque.</p>
<p>Une fois sur l'interface classique d'Ubuntu (mais lancé depuis la clé), vous pouvez si c'est nécessaire formater votre disque avec l'application gnome disks pour avoir une machine "comme" neuve.</p>
<h2>Partitionner le disque</h2>
<p>Nous allons utiliser fdisk depuis le terminal avec "<em>ctrl-alt-t</em>" (ou bien "<em>super-a</em>" et rechercher le terminal).</p>
<p>Pour simplifier le processus et comme la plupart des commandes nécessitent un niveau de permission superuser, il faut entrer :</p>
<div class="highlight"><pre><span></span><code>sudo -s
</code></pre></div>
<p>Ensuite, vous pouvez lister les disques disponibles avec :</p>
<div class="highlight"><pre><span></span><code>fdisk -l
</code></pre></div>
<p>Le disque en question sera probablement <code>/dev/sda</code> ou <code>/dev/vda</code> pour moi c'était plutôt <code>/dev/nvme0n1</code>. La suite de cette doc suivra les particularités de ma machine.</p>
<p>Pour <strong>partitionner</strong> ce disque, entrez :</p>
<div class="highlight"><pre><span></span><code>fdisk /dev/nvme0n1
</code></pre></div>
<p>Il nous faut une partition <strong>EFI</strong>, une partition de <strong>boot</strong>, et une autre partition (celle qui sera <strong>chiffrée</strong>) qui occupera le reste du disque. Dans fdisk, pour obtenir de l'aide, appuyez sur "<em>m</em>" et en cas de doute sur les différentes partitions, vous pouvez appuyer sur "<em>q</em>" pour quitter sans sauvegarder vos modifications.</p>
<h3>EFI</h3>
<p>Pour créer la première partition EFI, appuyez sur</p>
<div class="highlight"><pre><span></span><code>n
</code></pre></div>
<p>Le prompt va alors vous demander le numéro de la partition, gardez la valeur par défaut en pressant</p>
<div class="highlight"><pre><span></span><code>↵
</code></pre></div>
<p>Ensuite, il vous demande quel est le premier secteur à allouer. Par défaut, ce sera le premier qu'il trouve, appuyez donc sur</p>
<div class="highlight"><pre><span></span><code>↵
</code></pre></div>
<p>Et enfin le dernier secteur. Cette partition de EFI de nécessite pas de beaucoup de place. Mais suffisant, ce n'est pas assez pour moi, j'ai donc arbitrairement préféré 2G parce que mon disque est assez gros pour supporter un sacrifice de cette valeur. Indiquez dans le prompt</p>
<div class="highlight"><pre><span></span><code>+2G
</code></pre></div>
<h3>Boot</h3>
<p>Pour la partition de boot, même procédure, 2G c'est trop, généralement, 512M sont suffisant, mais trop, c'est pas grave aussi :</p>
<div class="highlight"><pre><span></span><code>n
↵
↵
+2G
</code></pre></div>
<h3>À chiffrer</h3>
<p>Enfin pour la dernière partition, même procédure, sauf que l'on veut occuper le reste du disque. Le dernier secteur de cette partition doit donc être le dernier secteur du disque, et ça tombe bien, c'est la valeur par défaut :</p>
<div class="highlight"><pre><span></span><code>n
↵
↵
↵
</code></pre></div>
<p>Il faut maintenant sauvegarder toutes ces modifications de la table de partition en pressant</p>
<div class="highlight"><pre><span></span><code>w
</code></pre></div>
<p>Les partitions sont maintenant créées, nous pouvons passer au chiffrement de cette dernière partition nommée <code>nvme0n1p3</code>.</p>
<h2>Chiffrer votre partition principale</h2>
<p>Il est temps de choisir un nom pour votre volume chiffré. Vous pouvez par exemple choisir le nom que vous voulez donner à votre machine. Lors du lancement de votre ordinateur, c'est ce nom qui apparaîtra lorsque vous sera demandé votre mot de passe pour <strong>déchiffrer</strong> le disque. Ici, pour l'exemple, nous l'appellerons <code>pasvraimentcrypté</code>.</p>
<p>Nous pouvons lancer la procédure de chiffrement avec</p>
<div class="highlight"><pre><span></span><code>cryptsetup luksFormat /dev/nvme0n1p3
</code></pre></div>
<p>Le prompt demandera confirmation en entrant YES ce que nous pouvons faire en toute sérénité. Il demandera ensuite d'entrer la <strong>passphrase</strong>, ce sera votre clé pour déchiffrer votre disque à chaque démarrage, ne l'oubliez pas !</p>
<p>Nous avons ensuite besoin d'ouvrir cette partition chiffrée, pour en faire un volume physique et pour y créer un groupe de volume nommé ubuntu et différents volumes logiques. Entrons</p>
<div class="highlight"><pre><span></span><code>cryptsetup luksOpen /dev/nvme0n1p3 pasvraimentcrypté
</code></pre></div>
<p>Comme nous ouvrons un volume chiffré, le prompt nous demande la passphrase. Cette commande va créer un nouveau device nommé <code>/dev/mapper/pasvraimentcrypté</code>.</p>
<p>Nous allons ensuite utiliser LVM2 (Logical Volume Manager) pour <strong>partitionner</strong> ce nouveau device. Dans notre cas, nous voulons une partition <strong>root</strong> de minimum 8G pour l'OS, une partition <strong>home</strong> pour l'utilisateur et une partition <strong>swap</strong> de 8G pour la mémoire. Vous pouvez être imaginatif sur vos partition, vous trouverez beaucoup de ressources et différents avis sur la question de la taille à allouer, mais ce cas suffit à mes besoins.</p>
<p>Nous allons faire de notre partition déchiffrée un volume physique :</p>
<div class="highlight"><pre><span></span><code>pvcreate /dev/mapper/pasvraimentcrypté
</code></pre></div>
<p>Puis créer un groupe <em>ubuntu</em> (ou autre) :</p>
<div class="highlight"><pre><span></span><code>vgcreate ubuntu /dev/mapper/pasvraimentcrypté
</code></pre></div>
<p>Et enfin les volumes logiques du groupe <em>ubuntu</em> :</p>
<div class="highlight"><pre><span></span><code>lvcreate -L 64G -n root ubuntu
lvcreate -L 8G -n swap ubuntu
lvcreate -l 100%FREE -n home ubuntu
</code></pre></div>
<p>Nous pouvons maintenant relancer l'installeur. Lorsque celui-ci demandera de choisir le type d'installation, cliquez sur le bouton "<strong>Autre chose</strong>", ce qui nous permettra d'utiliser les partitions et volumes créés. Configurons les trois volumes logiques :</p>
<ul>
<li>
<p><code>/dev/mapper/ubuntu-root</code></p>
<ul>
<li>Utiliser comme : Ext4 journaling filesystem</li>
<li>Formater la partition</li>
<li>Point de montage : <code>/</code></li>
</ul>
</li>
<li>
<p><code>/dev/mapper/ubuntu-swap</code></p>
<ul>
<li>Utiliser comme : Swap area</li>
</ul>
</li>
<li>
<p><code>/dev/mapper/ubuntu-home</code></p>
<ul>
<li>Utiliser comme : Ext4 journaling filesystem</li>
<li>Formater la partition</li>
<li>Point de montage : <code>/home</code></li>
</ul>
</li>
</ul>
<p>Et pour les devices :</p>
<ul>
<li>
<p>/dev/nvme0n1p1</p>
<ul>
<li>Utiliser comme : EFI</li>
</ul>
</li>
<li>
<p>/dev/nvme0n1p2</p>
<ul>
<li>Utiliser comme : Ext2 filesystem</li>
<li>Formater la partition</li>
<li>Point de montage : <code>/boot</code></li>
</ul>
</li>
</ul>
<p>Un petit récapitulatif des changement sera affiché. Nous pouvons poursuivre l'installation d'Ubuntu. Une fois l'installation terminée, choisissez "Continuer à tester", nous devons encore faire un peu de configuration.</p>
<h2>Instructions de déchiffrement au démarrage</h2>
<p>Ubuntu est installé sur votre machine. Il nous faut maintenant décrire quel device doit être <strong>déchiffré au démarrage et comment</strong>. Nous avons donc besoin d'éditer la crypttab pour donner ces instructions. Pour que tout cela soit pris en compte, il nous faut reconstruire initramfs qui gère le répertoire racine temporaire pendant le démarrage du système. Enfin, cette reconstruction ne peut être réalisée que depuis la nouvelle installation.</p>
<p>Mais avant tout, il nous faut copier l'<strong>UUID</strong> du disque chiffré. Ouvrez un nouveau terminal (ou un nouvel onglet) et entrez</p>
<div class="highlight"><pre><span></span><code>sudo blkid /dev/nvme0n1p3
</code></pre></div>
<p>vous pourrez par la suite retourner sur cet onglet, il vous suffira de le mettre en surbrillance pour qu'il soit copié dans le buffer de votre souris (et collé avec le bouton du milieu de votre souris). Vous pouvez aussi utiliser "<em>shift+ctrl+c</em>" pour copier le texte en surbrillance et "<em>shift+ctrl+v</em>" pour le coller.</p>
<h3>Basculer sur la nouvelle installation</h3>
<p>Nous allons utiliser chroot pour passer dans le nouveau système. Entrez les commandes suivantes :</p>
<div class="highlight"><pre><span></span><code>mount /dev/mapper/ubuntu-root /mnt
mount --bind /dev /mnt/dev
chroot /mnt
mount -t proc proc /proc
mount -t sysfs sys /sys
mount -t devpts devpts /dev/pts
mount -a
</code></pre></div>
<p>Nous sommes maintenant dans le nouveau système, avec différents devices montés sur différents répertoires.</p>
<h3>Instructions de démarrage</h3>
<p>Nous devons créer le fichier <code>/etc/crypttab</code>. Le fichier doit contenir la ligne suivante, vous pouvez l'éditer avec nano, vi, emacs, bref, votre éditeur préféré et il n'est évidemment pas nécessaire ici de débattre de la supériorité de l'un par rapport aux autres 😘</p>
<div class="highlight"><pre><span></span><code>pasvraimentcrypté   UUID=e7167ac4-b606-4be0-98a7-ace4e5e13f6b   none    luks,discard
</code></pre></div>
<p>Nous avons donc quatre champs : le nom du device à déchiffrer, son UUID (remplacez-le par celui de votre device chiffré, celui que vous avez copié précédemment, sans guillemets), le mot de passe (à none puisque l'objectif est qu'il vous soit demandé à chaque démarrage) et des options.</p>
<p>Sauvegardez ce fichier et quittez l'éditeur (pas le terminal).</p>
<h3>Mettre à jour initramfs</h3>
<p>Une fois l'éditeur quitté, toujours dans le terminal, il nous suffit de rentrer la commande suivante :</p>
<div class="highlight"><pre><span></span><code>update-initramfs -k all -u
</code></pre></div>
<p>Nous pouvons maintenant quitter <code>chroot</code> en tapant</p>
<div class="highlight"><pre><span></span><code><span class="k">exit</span>
</code></pre></div>
<p>Depuis notre shell de départ, il nous faut maintenant démonter <code>mnt</code> avec</p>
<div class="highlight"><pre><span></span><code>umount -R /mnt
</code></pre></div>
<h1>Fin</h1>
<p>Nous pouvons maintenant fermer le shell et <strong>relancer</strong> la machine. Au démarrage, elle devrait nous demander la <strong>passphrase</strong> pour déchiffrer le device <code>pasvraimentcrypté</code> puis Ubuntu se lancera normalement.</p>
<p>La commande :</p>
<div class="highlight"><pre><span></span><code>lsblk
</code></pre></div>
<p>nous permet d'avoir un visuel sur le résultat de nos différentes manipulations :</p>
<div class="highlight"><pre><span></span><code><span class="n">NAME</span><span class="w">                      </span><span class="nl">MAJ</span><span class="p">:</span><span class="nf">MIN</span><span class="w"> </span><span class="n">RM</span><span class="w">   </span><span class="k">SIZE</span><span class="w"> </span><span class="n">RO</span><span class="w"> </span><span class="n">TYPE</span><span class="w">  </span><span class="n">MOUNTPOINT</span>
<span class="n">nvme0n1</span><span class="w">                   </span><span class="mi">259</span><span class="err">:</span><span class="mi">0</span><span class="w">    </span><span class="mi">0</span><span class="w"> </span><span class="mi">476</span><span class="p">,</span><span class="mi">9</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="k">disk</span>
<span class="err">├─</span><span class="n">nvme0n1p1</span><span class="w">               </span><span class="mi">259</span><span class="err">:</span><span class="mi">1</span><span class="w">    </span><span class="mi">0</span><span class="w">     </span><span class="mi">2</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">part</span><span class="w">  </span><span class="o">/</span><span class="n">boot</span><span class="o">/</span><span class="n">efi</span>
<span class="err">├─</span><span class="n">nvme0n1p2</span><span class="w">               </span><span class="mi">259</span><span class="err">:</span><span class="mi">2</span><span class="w">    </span><span class="mi">0</span><span class="w">     </span><span class="mi">2</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">part</span><span class="w">  </span><span class="o">/</span><span class="n">boot</span>
<span class="err">└─</span><span class="n">nvme0n1p3</span><span class="w">               </span><span class="mi">259</span><span class="err">:</span><span class="mi">3</span><span class="w">    </span><span class="mi">0</span><span class="w"> </span><span class="mi">472</span><span class="p">,</span><span class="mi">9</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">part</span>
<span class="w">  </span><span class="err">└─</span><span class="n">pasvraimentcrypté</span><span class="w">     </span><span class="mi">253</span><span class="err">:</span><span class="mi">0</span><span class="w">    </span><span class="mi">0</span><span class="w"> </span><span class="mi">472</span><span class="p">,</span><span class="mi">9</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">crypt</span>
<span class="w">    </span><span class="err">├─</span><span class="n">ubuntu</span><span class="o">-</span><span class="n">root</span><span class="w">         </span><span class="mi">253</span><span class="err">:</span><span class="mi">1</span><span class="w">    </span><span class="mi">0</span><span class="w">    </span><span class="mi">64</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">lvm</span><span class="w">   </span><span class="o">/</span>
<span class="w">    </span><span class="err">├─</span><span class="n">ubuntu</span><span class="o">-</span><span class="n">swap</span><span class="w">         </span><span class="mi">253</span><span class="err">:</span><span class="mi">2</span><span class="w">    </span><span class="mi">0</span><span class="w">     </span><span class="mi">8</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">lvm</span><span class="w">   </span><span class="o">[</span><span class="n">SWAP</span><span class="o">]</span>
<span class="w">    </span><span class="err">└─</span><span class="n">ubuntu</span><span class="o">-</span><span class="n">home</span><span class="w">         </span><span class="mi">253</span><span class="err">:</span><span class="mi">3</span><span class="w">    </span><span class="mi">0</span><span class="w"> </span><span class="mi">400</span><span class="p">,</span><span class="mi">9</span><span class="n">G</span><span class="w">  </span><span class="mi">0</span><span class="w"> </span><span class="n">lvm</span><span class="w">   </span><span class="o">/</span><span class="n">home</span>
</code></pre></div>
<p>On peut résumer cela ainsi :</p>
<ul>
<li>le disque physique <code>nvme0n1</code> est divisé en trois partitions physiques : <code>nvme0n1p1</code>, <code>nvme0n1p2</code> et <code>nvme0n1p3</code></li>
<li>la partition <code>nvme0n1p1</code> est une partition EFI (nécessaire depuis Ubuntu 20.04) requise par le système d'exploitation</li>
<li>la partition <code>nvme0n1p2</code> est la partie <code>/boot</code> qui permet au système de démarrer</li>
<li>la partition <code>nvme0n1p3</code> contient un volume chiffré <code>pasvraimentcrypté</code></li>
<li>ce volume chiffré <code>pasvraimentcrypté</code> que l'on doit déchiffrer au démarrage contient les trois volumes logiques LVM suivants :</li>
<li><code>ubuntu-root</code>, la racine de l'arborescence du système Ubuntu</li>
<li><code>ubuntu-swap</code>, l'extension de mémoire vive</li>
<li><code>ubuntu-home</code>, contenant les dossiers et fichiers personnels des utilisateurs, isolé du reste du système</li>
</ul>
<p>Ça y est, votre nouvelle vie commence avec votre nouvelle machine super secrète super rangée ! 🥳</p>
            </div>
        </content>
        <author>
            <name>Loan Robert &lt;loan@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Premier pied dans Yaal, en sabots</title>
        <link href="https://yaal.coop/blog/premier-pied-dans-yaal-en-sabots" />
        <id>https://yaal.coop/blog/premier-pied-dans-yaal-en-sabots</id>
        <updated>2021-10-17T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Mars 2020, un moment pas très bien choisi pour tenter de faire des entretiens d'embauche. Pourtant, je vois Yaal en visio d'abord, et j'apprécie beaucoup ce que j'entend pendant cet entretien !</p>
<p>On garde le contact, on se dit qu'on se verra après le confinement, mais comme les semaines s'étirent, on continue à distance et c'est le premier juillet 2020 et que je suis officiellement embauché⋅e dans Yaal en tant que graphiste webdesigner.</p>
<p><em>Ma première mission ?</em>
Développer l'identité visuelle du projet tout neuf de quelques associé⋅es de Yaal : <em>Une brasserie</em> !</p>
<h1>La Brasserie du Sabot, c'est quoi ?</h1>
<p>Le projet d'associé⋅es de Yaal. Une brasserie artisanale installée à Villenave d'Ornon, au sud de Bordeaux.</p>
<p>Un projet coopératif et militant. D'ailleurs, c'est pas pour rien que ça s'appelle le Sabot : Si au premier abord on va penser à l'aspect artisanal de la chaussure en bois d'antan, c'est plutôt du symbole révolutionnaire dont on parle ici. Le sabot qu'on coince dans les rouages de la machine à l'usine en signe de protestation. Le sabotage, quoi !</p>
<p>Pour moi, en tant que graphiste, ça fait deux grands axes à explorer pour concilier tout le monde :</p>
<ul>
<li>
<p>L'esthétique de l'engagement, de la contreculture, un truc un peu révolutionnaire. Militantisme, anarchisme, affichage sauvages, tracts syndicaux, pochoirs et graffitis, affiches déchirées, c'est ce genre d'images là que j'ai eu en tête.</p>
</li>
<li>
<p>L'artisanal. Le bois, le recyclé, le matériau brut, l'écologie. C'est aussi un sujet clé pour les associé⋅es de la brasserie.</p>
</li>
</ul>
<h2>Des idées en vrac</h2>
<p><img alt="Dessins de départ pour la brasserie" src="https://yaal.coop/media/blog/articles/dessins-initiaux.webp" title="dessins de départ pour la brasserie"/></p>
<p>Inspirations de dessin à la ligne claire, mais aussi de découpage de pochoir, puis de gravure.</p>
<h2>et ça sur des bouteilles, ça donnerait quoi ?</h2>
<p>Ces pistes, déclinées pleeein de fois sur des formats d'étiquette pour se donner une meilleure idée de ce que ça donne, ci-dessous un petit florilège :</p>
<p><img alt="Pistes et essais d'étiquettes" src="https://yaal.coop/media/blog/articles/design_tests_etiquette.webp" title="pistes et essais d'étiquettes"/></p>
<p>Toujours avec une texture un peu papier dans le fond, on se rappelle à la fois de l'aspect artisanal et des tracts de manif', une pierre deux coups.
Et pour s'y croire encore plus, j'en ai intégré certaines sur des mockups de bouteilles. Toujours plus d'immersion.</p>
<p><img alt="Mockups d'étiquettes sur des bouteilles" src="https://yaal.coop/media/blog/articles/bouteilles-mockup.webp" title="Mockups d'étiquettes sur des bouteilles"/></p>
<h2>Le choix final</h2>
<p>Avec ces prévisualisations en tête, plus simple de se faire une idée et de savoir ce qui nous parle vraiment.</p>
<p>Voilà le logo choisi, qui servira aussi pour les étiquettes d'expérimentation :</p>
<p><img alt="Logo final de la Brasserie du Sabot" src="https://yaal.coop/media/blog/articles/Logo_red.webp" title="Logo final de la Brasserie du Sabot"/></p>
<h2>Déclinaison</h2>
<p>Les étiquettes finales mettront à l'honneur des figures de l'anarchisme, et principalement des femmes !
En voilà quelques unes, à l'image d'Emma Goldman et Louise Michel.</p>
<p>Le logo principal quand à lui, se prête à l'exercice des brassins de test, du site internet, des flyers, des sous-bock et de la devanture de la brasserie elle-même.</p>
<p><img alt="Etiquettes finales (en situation ?)" src="https://yaal.coop/media/blog/articles/bouteilles-experimentation.webp" title="Etiquettes finales en situation"/>
<img alt="Etiquettes finales (en situation ?)" src="https://yaal.coop/media/blog/articles/bouteilles-finales.webp" title="Etiquettes finales en situation"/>
Les étiquettes finales, après retouches faites en interne à la brasserie.</p>
<h2>Le site</h2>
<p>Dans un premier temps, j'ai développé un site internet vitrine pour la Brasserie, dont l'objectif principal était d'annoncer sa future ouverture et de la faire découvrir.</p>
<p>Puis dans un second temps est venue la partie boutique, celle qui permet de commander ses bières en ligne !</p>
<p><img alt="Homepage du site de la brasserie" src="https://yaal.coop/media/blog/articles/homepage.webp" title="Homepage du site de la brasserie"/></p>
<p><img alt="Page boutique de la brasserie" src="https://yaal.coop/media/blog/articles/sabot-boutique.webp" title="Page boutique de la brasserie"/></p>
<h1>Tada !</h1>
<h2>Et surtout, n'hésitez pas à aller jeter un oeil par vous même sur 🍺 <a href="https://sabot.beer">https://sabot.beer</a> 🍺 !</h2>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Python 3.10</title>
        <link href="https://zestedesavoir.com/articles/4041/sortie-de-python-3-10/" />
        <id>https://zestedesavoir.com/articles/4041/sortie-de-python-3-10/</id>
        <updated>2021-10-11T23:40:42Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Ou autrement dit, le pattern matching en Python
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>De Yaal à Yaal Coop</title>
        <link href="https://yaal.coop/blog/de-yaal-a-yaal-coop" />
        <id>https://yaal.coop/blog/de-yaal-a-yaal-coop</id>
        <updated>2021-09-23T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p><strong>Yaal Coop</strong> est officiellement née le 1er septembre 2020 et a accueilli ses premier·es salarié·es 2 mois plus tard, en novembre 2020.
C'est la petite soeur de <a href="https://yaal.fr/">Yaal SAS</a>, créée il y a bien plus longtemps, en 2010 (ce qui ne rajeunit pas ses fondateurs Arthur et Colin !).</p>
<p>Comme je sais que la co-existence des deux entreprises peut être source de confusion, voici ma tentative pour raconter l'aventure Yaal Coop.</p>
<p><em>Disclaimer : mon point de vue est personnel et forcément biaisé. Et pas forcément très synthétique non plus.</em> 😗🎶</p>
<h2>Yaal kézako ?</h2>
<p>Yaal est une vieille entreprise d'informatique (sisi 2010 c'est forcément vieux, je n'avais même pas entamé ma première carrière professionnelle de bio-physicienne à cette époque !).
Mais une entreprise qui n'a de classique que son statut juridique de SAS, car pour le reste, on dévie pas mal des standards du milieu.</p>
<p><strong>Auto-organisation</strong> et <strong>auto-gouvernance</strong> sont des principes qui font partie de l'ADN de Yaal depuis toujours.
Si l'entreprise a grossi, jusqu'à atteindre une trentaine de personnes en 2019, elle a eu à coeur de maintenir ces principes en effaçant la hierarchie et en proposant aux salarié·es de s'associer après un an de collaboration.
Transparence des salaires et des finances permet à chacun·e, associé·e comme salarié·e, de saisir les enjeux, de se forger une opinion et d'en discuter lorsqu'il le désire.</p>
<p>Une autre particularité de Yaal est son modèle économique reposant sur <strong>l'investissement technique</strong>. L'ambition est grande : casser les règles habituelles du couple client/prestataire informatique en partageant les risques aussi bien techniques que financiers avec les porteur·euses de projets innovants auxquels elle s’associe.
Pour se donner les moyens de ces ambitions, les associé·es touchent tous le même salaire, sensiblement plus faible que le prix du marché pour permettre à l'entreprise d'investir dans les projets, et se partagent plus tard les bénéfices en cas de succès collectif. Finalement, sur 10 ans, les revenus des associés chez Yaal sont comparables à ceux d'autres entreprises informatiques.</p>
<p>Car cela marche : le plus gros projet de Yaal, <a href="https://myelefant.com/en/">Myelefant</a>, <a href="https://objectifaquitaine.latribune.fr/innovation/2019-11-14/comment-yaal-investit-de-la-technique-dans-les-startups-832940.html">est revendu 21 millions d'euros en novembre 2019</a> !</p>
<h2>Pourquoi créer Yaal Coop ?</h2>
<p>Avec le rachat de Myelefant par Sinch, une partie de l'équipe quitte Yaal pour suivre ce projet et rejoint Sinch en mars 2020.
Parmi ceux et celles qui font le choix de rester, des associé·es de Yaal de longue date mais aussi des salarié·es plus récent·es, dont je fais partie.</p>
<p>Embauchée à Yaal en octobre 2018, je n'ai pas eu le temps d'y devenir associée, l'opération de vente de Myelefant ayant gelé les opérations d'entrée et sortie du capital à l'été 2019.
Et après le rachat, la situation financière de Yaal a évidemment pas mal changé. Il n'est d'un coup plus aussi simple de rentrer au capital de Yaal SAS dont la valorisation financière a pas mal évolué. 😅</p>
<p>Pour autant j'aime toujours Yaal et son modèle inspirant qui m'a séduite d'entrée !
Et je ne suis pas la seule.</p>
<p>Alors que certain·es profitent de ce tournant pour se lancer dans une aventure de <a href="https://sabot.beer/">production de bière</a>, je commence un sacré remue-méninges avec mes collègues pour imaginer un Yaal 2.0 encore plus beau, encore plus fort, et encore plus autogestionné. 💪</p>
<p>Tant qu'à devoir changer de structure pour assurer à tous ses membres un même niveau d'engagement et de pouvoir décisionnel, pourquoi ne pas remettre les choses à plat et changer de statut ?
En passant à celui officiel de <strong>coopérative</strong>, cela clarifie notre fonctionnement (1 personne = 1 voix) et nos valeurs (recherche d'équilibre entre toutes les parties prenantes et d'une rentabilité compatible avec cet objectif).</p>
<h2>Qu'est-ce qui change alors dans Yaal Coop ?</h2>
<p>Yaal Coop est une Société Coopérative d'Intéret Collectif (SCIC). Entre autre, ça veut dire que :</p>
<ul>
<li>
<p>Tout·e salarié·e peut un jour devenir associé·e. Chez nous, c'est même devenu une obligation après un an de salariat, inscrite dans nos statuts. On souhaite ainsi aligner nos intérêts et nos engagements, éviter de créer un fossé entre coopérateur·rices associé·es et salarié·es. Fin 2019 à Yaal, un tiers seulement des salarié·es étaient associé·es et il nous semble nécessaire d'inverser la dynamique au sein de Yaal Coop.</p>
</li>
<li>
<p>Le processus d'entrée et sortie des associé·es au sein de la coopérative est simplifié car il est décrit dans nos statuts et détaché de la valorisation financière de l'entreprise, au contraire d'une entreprise classique. Cela assure également une lucrativité limitée puisque'aucune plus-value n’est possible lors du remboursement des parts en cas de départ.</p>
</li>
<li>
<p>Au contraire d'une SCOP (un autre statut plus connu des entreprises coopératives), le capital et le pouvoir n'est pas réservé aux seul·es salarié·es. Plusieurs collèges d'associé·es existent, dont celui des salarié·es, mais ce n'est pas le seul.</p>
</li>
</ul>
<p>Aujourd'hui à Yaal Coop nous avons désigné 4 collèges :</p>
<ul>
<li>
<p>celui des <strong>salarié·es</strong> qui dispose de 50% des voix, le maximum possible en SCIC, car il nous semble primordial que les travailleur·euses soient majoritaires pour décider des orientations de leur entreprise</p>
</li>
<li>
<p>celui des <strong>bénéficiaires</strong> (composé de clients, usagers ou fournisseurs). Collège obligatoire en SCIC, il fait toute la particularité de ce statut et concrétise la recherche de l'intérêt collectif, en intégrant les autres parties prenantes du travail réalisé au sein de l'entreprise</p>
</li>
<li>
<p>celui des <strong>investisseur·euses</strong> qui nous a permis d'accueillir Yaal SAS et de bénéficier d'un premier apport pour lancer l'activité !</p>
</li>
<li>
<p>et celui des <strong>observateur·rices et soutiens</strong>, qui vise à accueillir toute personne morale ou physique qui contribuerait par tout moyen à l'activité de Yaal Coop : professionnel·le collaborateur·rice, réseau ou organisme partenaire (acteur·rice de l'ESS, des biens communs...), bénévole, etc.</p>
</li>
</ul>
<p>Pour créer Yaal Coop, nous nous sommes fait accompagner par <a href="https://www.finacoop.fr/">Finacoop Nouvelle Aquitaine</a>, qui est aujourd'hui notre cabinet comptable mais aussi le premier membre officiel de notre collège des bénéficiaires 💚, ainsi que par l'URSCOP.</p>
<p>Nous avons aussi procédé à un rachat de l'activité partielle de Yaal SAS pour basculer nos contrats de travail, et nous avons signé un contrat de licence d'exploitation de la marque Yaal pour pouvoir porter fièrement l'héritage de Yaal jusque dans notre nom. ✊</p>
<h2>Mais concrètement au quotidien ça fonctionne comment ?</h2>
<p>Pour l'instant la mise en oeuvre de nos principes coopératifs et d'auto-gouvernance est plutôt simplifiée : en passant de plus de 30 salarié·es à <strong>5 coopérateur·rices salarié·es associé·es</strong>, on a naturellement beaucoup fluidifié la communication et le partage d'informations entre nous (même si la crise sanitaire ne nous a, elle, pas beaucoup aidés 😩).</p>
<p>Aujourd'hui on se retrouve la plupart des jours de la semaine en présentiel dans notre local pour travailler sur nos différents projets.
Même lorsqu'on ne travaille pas sur la même chose au même moment, c'est d'autant plus facile de discuter des autres sujets autour d'une pause thé ou du déjeuner.</p>
<p>Le mardi en particulier est sanctuarisé pour pouvoir discuter et travailler sur des sujets collectifs : tout le monde se retrouve au bureau et personne ne travaille isolé en prestation. <em>(Au contraire le mercredi est le seul jour où tout le monde télétravaille alors ne prévoyez pas de passer au local ce jour là pour boire un café !).</em></p>
<p>Lorsque tout le monde est arrivé, on commence notre <strong>weekly</strong> où l'on discute à tour de rôle des activités de la semaine passée et celle à venir en s'appuyant sur notre trello* d'équipe qu'on met à jour à ce moment là. On y met en particulier toutes les tâches de gestion, projets internes et pistes/prospects pour assurer un suivi partagé.</p>
<p>Avec notre instance de cloud nextcloud qui nous permet de numériser et ranger tous les documents de l'entreprise (notamment les factures, contrats, fiches de paie, etc.) et de partager des agendas (par exemple celui de nos congés/absences), c'est notre outil principal pour la gestion.</p>
<p>On a aussi une petite interface maison héritée de Yaal qui nous permet à tous d'avoir un oeil sur l'évolution du compte en banque, un bon gros tableau libre office à l'ancienne en guise de plan de tréso et un mini-wiki dans un simple document texte partagé pour documenter nos habitudes de gestion, qu'on étoffe au fur et à mesure (comment on commande des tickets resto ? Comment on range une facture ? Comment on fait la paie <em>(sans risquer d'oublier la dernière étape de bien fêter la fête 🎉)</em> ?).</p>
<p>Les mails et surtout la messagerie Element complètent nos outils de communication interne, en particulier les jours où nous sommes à distance et/ou asynchrones.</p>
<p>De manière plus macro, on a fait le choix du <strong>salaire unique</strong> et du <strong>temps plein</strong> pour les associé·es.
Notre salaire est donc indépendant de notre expérience, de notre fonction et du montant que l'on facture.
Et son montant est encore bas pour continuer de pouvoir investir à la manière de Yaal SAS.</p>
<p>On a eu pas mal de discussions riches sur le sujet, en particulier une session animée par <a href="https://davidbruant.github.io/">David Bruant</a>, extérieur à la coop, qui aime réfléchir au sujet de la rémunération juste (merci d'être venu en parler avec nous l'année dernière !).
Je suis assez curieuse d'autres modèles alternatifs, comme celui de <a href="http://scopyleft.fr/">Scopyleft</a> par exemple, où chacun se paie ce dont il a besoin après avoir pris soin d'en discuter avec tout le monde.</p>
<p>Mais pour l'instant le salaire unique nous convient et nous permet de démarrer simplement. On aimerait s'augmenter dès que la coopérative aura atteint un régime de croisière mais on est aussi plus dans la team "réduisons notre temps de travail" que "gagnons toujours plus", donc on verra bien...</p>
<p>Côté projets, on continue l'investissement technique (comme avec notre premier projet <a href="https://lum1.fr/">Lum1</a> !), mais on fait aussi un peu de bénévolat à <a href="https://supercoop.fr/">Supercoop</a> (le supermarché coopératif de Bordeaux) et d'autres projets internes : bientôt <a href="https://nubla.io">Nubla</a> ☁️ ?! On fait aussi un peu de prestation plus classique vu qu'on continue notamment à travailler pour Sinch, ce qui assure une certaine stabilité financière.</p>
<p>Au fond on cherche encore l'équilibre qui conviendra (et qui évoluera probablement !) et on est ouvert sur les modes de collaboration possibles.
Ce que l'on veut surtout c'est <strong>participer à des projets qui ont du sens</strong> et <strong>avec des personnes qui partagent nos valeurs</strong>.</p>
<p>Enfin côté vie coopérative élargie, et en particulier animation des autres collèges d'associé·es, on a encore un tas de chose à explorer. On a la chance de pouvoir commencer petits, avec peu d'associé·es qui nous connaissent et nous font confiance. Donc nos efforts sont pour l'instant concentrés ailleurs. Mais on a en tête que c'est une chose à laquelle on va devoir consacrer plus de temps ensuite ! Et on a hâte d'avoir les moyens de le faire.</p>
<p>Yaal Coop n'a même pas un an, on n'est qu'au début de l'aventure et de l'expérimentation ! 🌱</p>
<h2>Et Yaal SAS alors ?</h2>
<p>Je suis sans doute mal placée pour parler de Yaal SAS car je n'en fais plus partie. Son activité est aujourd'hui en sommeil, il n'y a d'ailleurs plus aucun salarié : seulement <a href="https://www.yaal.fr/equipe">9 associé.es</a> dispersés entre Yaal Coop, Sinch, La Brasserie du Sabot et d'autres projets personnels. Dispersés mais pas bien loin, alors rendez-vous à la prochaine bière ! 🍻</p>
<p><em>*Oui Trello. L'outil détonne au milieu des autres outils libres qu'on utilise et dont on est plus friand. Mais pour l'instant on n'a pas trouvé d'alternative cool et aussi pratique pour la gestion de projet donc on fait avec 🙂 (vous utilisez quoi vous ?)</em></p>
            </div>
        </content>
        <author>
            <name>Camille Daniel &lt;camille@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Python 3.10 : récapitulatif des nouveautés</title>
        <link href="https://www.olivierpons.fr/2021/09/16/python-3-10-recapitulatif-des-nouveautes/" />
        <id>https://www.olivierpons.fr/2021/09/16/python-3-10-recapitulatif-des-nouveautes/</id>
        <updated>2021-09-17T00:23:45Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h2><a href="https://www.python.org/dev/peps/pep-0604/" rel="noopener" target="_blank">Pep 604</a></h2>
<p>Tester plusieurs types avec le <code>|</code> :</p>
<p><code>isinstance(5, int | str)<br/>
isinstance(None, int | None)<br/>
isinstance(42, None | int)<br/>
issubclass(bool, int | float)</code></p>
<p>Même chose pour les annotations :</p>
<p><code>def ma_fonction(<br/>
        ma_liste: List[int | str],<br/>
        param: int | None<br/>
    ) -&gt; float | str:<br/>
    pass</code></p>
<h2>Messages d’erreur plus parlants</h2>
<ul>
<li>L’erreur est maintenant affichée à la ligne de début du problème, et non plus lorsque l’interpréteur n’y comprend plus rien, l’exemple le plus marquant étant avec l’oubli d’une parenthèse fermante, ou d’une mauvaise indentation</li>
<li>Les messages ont été corrigés de manière à ce qu’ils soient plus clairs, avec des suggestions très utiles qui correspondent souvent à l’erreur</li>
</ul>
<h2>Le match/case</h2>
<p>Le match/case de Python est similaire à l’instruction switch/case, qui est reconnue comme un « pattern matching structurel » en Python.</p>
<p>Le match/case de Python se compose de trois entités principales :</p>
<ol>
<li>Le mot-clé <code>match</code></li>
<li>Une ou plusieurs clauses <code>case</code></li>
<li>Du code pour chaque <code>case</code></li>
</ol>
<p>Là où Python se démarque des autres langages, c’est que l’on peut faire un <code>match</code> sur des <strong>patterns</strong> !</p>
<p>Exemples de <code>match</code>, du plus simple au plus avancé :</p>
<hr/>
<h3>Match très simple, avec le « or »</h3>
<p><code>exemple = True<br/>
match exemple:<br/>
    case (True|False):<br/>
        print("C'est un booléen")<br/>
    case _ :<br/>
        print("Ce n'est pas un booléen")</code></p>
<hr/>
<h3>Récupérer les sous-patterns</h3>
<p><code>def alarm(item):<br/>
    match item:<br/>
        case [time, action]:<br/>
            print(f"{time} ! C'est l'heure de {action}!")<br/>
        case [time, *actions]:<br/>
            print(f'{time} !')<br/>
            for action in actions:<br/>
                print(f"C'est l'heure {action}!")<br/>
alarm(['Bon après-midi', 'de travailler'])<br/>
alarm(['Bonjour', 'du petit déjeuner', 'se laver les dents'])</code></p>
<hr/>
<h3>Nommer les sous-patterns</h3>
<p><code>def alarme(item):<br/>
    match item:<br/>
        case [('bonjour' | 'bonsoir') <strong>as time</strong>, action]:<br/>
            print(f"{time.title()} ! Il faudrait {action} !")<br/>
        case _:<br/>
            print('Mot-clé invalide.')<br/>
alarme(['bonsoir', 'travailler'])<br/>
alarme(['bonjour', 'petit déjeuner', 'se laver les dents'])</code></p>
<hr/>
<h3>Nommer les sous-patterns et filtres conditionnels</h3>
<p><code>def alarme(item):<br/>
    match item:<br/>
        case ['bonsoir', action] <strong>if action not in</strong> ['travailler']:<br/>
            print(f'Journée finie ! Il faut {action}!')<br/>
        case ['bonsoir', _]:<br/>
            print('Il faut se reposer !')<br/>
        case [time, *action]:<br/>
            print(f'{time.title()}! Il faut {" et ".join(action)}.')<br/>
        case _:<br/>
            print('Mot-clé invalide.')<br/>
alarme(['bonsoir', 'travailler'])<br/>
alarme(['bonsoir', 'jouer'])<br/>
alarme(['bonjour', 'petit déjeuner', 'se laver les dents'])</code></p>
<hr/>
<h3>Match sur des objets</h3>
<p><code>class Move:<br/>
    def __init__(self, horizontal=None, vertical=None):<br/>
        self.horizontal = horizontal<br/>
        self.vertical = vertical<br/>
def str_move(move):<br/>
    match move:<br/>
        case Move(horizontal='est', vertical='nord'):<br/>
            print('Dir. nord-est')<br/>
        case Move(horizontal='est', vertical='sud'):<br/>
            print('Dir. sud-est')<br/>
        case Move(horizontal='ouest', vertical='nord'):<br/>
            print('Dir. nord-ouest')<br/>
        case Move(horizontal='ouest', vertical='sud'):<br/>
            print('Dir. sud ouest')<br/>
        case Move(horizontal=None):<br/>
            print(f'Dir. {move.vertical}')<br/>
        case Move(vertical=None):<br/>
            print(f'Dir. {move.horizontal}')<br/>
        case _:<br/>
            print('? Move inconnu ?')<br/>
d1 = Move('est', 'sud')<br/>
d2 = Move(vertical='nord')<br/>
d3 = Move('centre', 'centre')<br/>
str_move(d1)<br/>
str_move(d2)<br/>
str_move(d3)</code></p>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Design et création d&#39;un nuage, Nubla.io</title>
        <link href="https://yaal.coop/blog/design-et-creation-d-un-nuage-nubla-io" />
        <id>https://yaal.coop/blog/design-et-creation-d-un-nuage-nubla-io</id>
        <updated>2021-09-06T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1>C'est quoi, Nubla ?</h1>
<p>Nubla, c'est un projet de service pour fournir des e-mails, de l'espace de stockage Cloud, de messagerie instantanée et d'agenda pour tous⋅tes, sans passer sous le giron de Google et des géants du web.</p>
<p>On veut passer par des solutions libres, mises à disposition à des frais qui varient selon les moyens de nos utilisateurs. Ca, on y tient. C'est un souhait aussi depuis le début, s'adapter et faire un service qui puisse profiter à un maximum de monde, sans vente de données, sans fins publicitaires et sur mesure.</p>
<p><img alt="Bannière nubla.io" src="https://yaal.coop/media/blog/articles/meta-picture.webp" title="bannière nubla.io"/></p>
<h1>☁️</h1>
<hr/>
<h1>Design et création d'un nuage, Nubla.io ☁️</h1>
<p>Ma priorité sur le site de Nubla, c'est de faire un site internet fonctionnel, accessible et lisible. Et quand je dis accessible, c'est au sens de l'accessibilité à tous⋅tes : Choix de polices d'écriture intelligibles, contrastes suffisants, hiérarchisation des contenus et facilité de navigation.</p>
<p>La seconde, c'est de créer quelque chose qui me fasse plaisir à imaginer, à dessiner, puis à intégrer.</p>
<p>Utiliser des outils et des techniques qui me plaisent : <a href="https://wwW.coolors.co">coolors</a> pour le choix des palettes de couleur, me tourner vers des polices d'écriture libres, des illustrations open source aussi avec <a href="https://www.undraw.co">undraw</a>, l'utilisation de <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout">CSS Grid</a> pour l'intégration...</p>
<h2>Premières pistes</h2>
<p><img alt="Palettes, tests de fonts avec le texte nubla.io" src="https://yaal.coop/media/blog/articles/palettes-fonts.webp" title="Palettes, tests de fonts avec le texte nubla.io"/></p>
<p>Quand j'ai proposé au vote les différentes palettes à l'équipe, on s'en est sortis avec une égalité retentissante.</p>
<p>Le point commun entre toutes : Elles sont colorées. Vraiment.
Dans mes préférences, j'aimerais garder au moins une palette qui contient du jaune pour faire une petite référence discrète à Yaal Coop.</p>
<p>Parmi les autres couleurs, je tiens généralement à utiliser un noir qui n'est pas parfaitement noir, et un blanc pas parfaitement blanc. Juste pour ne pas trop agresser la rétine, je trouve ça plus doux. Ici, #323232 fait office de noir, et #F4F4F4 fait office de blanc.</p>
<h3>Les fonts testées ici sont :</h3>
<ul>
<li><a href="https://indestructibletype.com/Jost.html">Jost</a> - Une police d'écriture libre, adaptée à la technologie <a href="https://v-fonts.com/">variable font d'OpenType</a>, reproduisant l'esprit de la légendaire Futura.</li>
<li>Varela Round - Une police d'écriture ronde, sympathique, créée par le designer <a href="https://dribbble.com/JoePrince">Joe Prince</a>.</li>
</ul>
<p>J'ai finalement opté pour Jost, du fait de sa grande polyvalence, mais également pour son aspect géométrique et lisible qui viendra contraster avec les motifs décoratifs plutôt ronds du site (les fameux blobs).</p>
<p><img alt="Tests d'interaction des couleurs entre elles" src="https://yaal.coop/media/blog/articles/color-shapes.webp" title="Tests d'interaction des couleurs entre elles"/></p>
<p>Côté formes, décoratives, j'ai testé le géométrique et l'anguleux, mais pour un projet cloud avec une face amicale/familiale, je lui ai préféré les courbes et les "blobs" arrondis. La police d'écriture choisie elle-même déjà tout en angles et en pointes créée un contraste et une dynamique amusants.</p>
<p><img alt="Image du blob de fond" src="https://yaal.coop/media/blog/articles/blob.webp" title="image du blob de fond"/></p>
<h2>Wireframes</h2>
<p>Sur la sturcture du site, j'avais très envie de travailler avec <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout">CSS Grid</a> Je suis partie sur une structure de cinq colonnes, chacune séparée d'une gouttière de 20px, la première et la dernière colonne restant "vides" pour aérer le site. Je met vides entre guillemets, parce que c'est dans la colonne de droite que j'ai prévu de poser la navigation, fixée en haut à droite de l'écran pour rester toujours visible.</p>
<p><img alt="Wireframe de la page d'accueil, en noir et blanc" src="https://yaal.coop/media/blog/articles/wireframe-1.webp" title="Wireframe de la page d'accueil, en noir et blanc"/></p>
<p><img alt="Wireframe de la page à propos, en noir et blanc" src="https://yaal.coop/media/blog/articles/wireframe-3.webp" title="Wireframe de la page à propos, en noir et blanc"/></p>
<h2>Déclinaison de maquettes</h2>
<p>Les maquettes ci-dessous ne sont pas finales, mais sont là pour donner une idée assez claire des différents layouts qui seront mis en place sur le site et du rendu qu'on pourra obtenir.</p>
<p>Je suis pas vraiment adepte des maquettes pixel perfect (je vais pas m'étaler là dessus), d'autant plus lorsque je ne suis pas seul responsable des contenus du site. Je préfère poser une base, voir quels contenus sont proposés puis m'y adapter en respectant l'esprit et les déclinaisons de layouts choisis pour le site.</p>
<p><img alt="Maquettes graphiques du site Nubla.io" src="https://yaal.coop/media/blog/articles/maquette-homepage.webp" title="Maquettes graphiques du site Nubla.io"/></p>
<p><img alt="Maquettes graphiques du site Nubla.io" src="https://yaal.coop/media/blog/articles/maquette-about.webp" title="Maquettes graphiques du site Nubla.io"/></p>
<p>Pourquoi le cadre ? Jeu sur la structure du site, évite la sensation de "flottement" des éléments dans le vide. Peut aussi permettre des jeux de parallaxe.
Jouer avec le scroll à l'intérieur du cadre, avec la navigation fixe, je trouve ça assez marrant.</p>
<h1>☁️</h1>
<hr/>
<h1>Le Site</h1>
<h2>Structure du site :</h2>
<p><img alt="Schéma de la structure du site" src="https://yaal.coop/media/blog/articles/wireframe-grid.webp" title="Schéma de la structure du site"/></p>
<ul>
<li>Le body, sur lequel je place le blob de fond.</li>
<li>Un conteneur, celui qui a le cadre noir et un padding qui laisse la place pour la scrollbar à droite et les notes de pied de page en bas</li>
<li>Un layout en grille CSS de 5 colonnes, séparées par des gouttières de 20px.</li>
<li>La navigation, qui semble posée sur la 5eme colonne mais est en réalitée positionnée en position:fixed; pour ne pas bouger d'un pouce lorsque l'on navigue sur la page.</li>
</ul>
<h2>Les petits détails qui font plaiz</h2>
<p>... ou comment faire l'effet de soulignement dynamique des liens :</p>
<p><img alt="Gifs de quelques interactions animées, genre le soulignage des liens" src="https://yaal.coop/media/blog/articles/link-hover.gif" title="gif d'interaction animée"/></p>
<h3>C'est fait comme ça :</h3>
<div class="highlight"><pre><span></span><code><span class="p">.</span><span class="nc">line</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="kc">inline-block</span><span class="p">;</span>
<span class="w">    </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">relative</span><span class="p">;</span>
<span class="w">    </span><span class="k">font-style</span><span class="p">:</span><span class="w"> </span><span class="kc">normal</span><span class="p">;</span>
<span class="w">    </span><span class="k">z-index</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w">    </span><span class="k">color</span><span class="p">:</span><span class="nf">var</span><span class="p">(</span><span class="nv">--dark</span><span class="p">);</span>
<span class="p">}</span>

<span class="nt">a</span><span class="p">.</span><span class="nc">line</span><span class="p">:</span><span class="nd">hover</span><span class="o">,</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">line</span><span class="p">:</span><span class="nd">focus</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">color</span><span class="p">:</span><span class="nf">var</span><span class="p">(</span><span class="nv">--dark</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">.</span><span class="nc">line</span><span class="p">::</span><span class="nd">after</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="w">    </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mf">.7</span><span class="kt">em</span><span class="p">;</span>
<span class="w">    </span><span class="k">content</span><span class="p">:</span><span class="s2">" "</span><span class="p">;</span>
<span class="w">    </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--yellow</span><span class="p">);</span>
<span class="w">    </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">absolute</span><span class="p">;</span>
<span class="w">    </span><span class="k">left</span><span class="p">:</span><span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
<span class="w">    </span><span class="k">bottom</span><span class="p">:</span><span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
<span class="w">    </span><span class="k">z-index</span><span class="p">:</span><span class="w"> </span><span class="mi">-2</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">a</span><span class="p">.</span><span class="nc">line</span><span class="p">::</span><span class="nd">before</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="kt">%</span><span class="p">;</span>
<span class="w">    </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mf">.7</span><span class="kt">em</span><span class="p">;</span>
<span class="w">    </span><span class="k">content</span><span class="p">:</span><span class="s2">" "</span><span class="p">;</span>
<span class="w">    </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--magenta</span><span class="p">);</span>
<span class="w">    </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">absolute</span><span class="p">;</span>
<span class="w">    </span><span class="k">left</span><span class="p">:</span><span class="mi">10</span><span class="kt">px</span><span class="p">;</span>
<span class="w">    </span><span class="k">bottom</span><span class="p">:</span><span class="mi">0</span><span class="kt">px</span><span class="p">;</span>
<span class="w">    </span><span class="k">z-index</span><span class="p">:</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
<span class="w">    </span><span class="k">transition</span><span class="p">:</span><span class="w"> </span><span class="mf">.2</span><span class="kt">s</span><span class="w"> </span><span class="kc">all</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">a</span><span class="p">.</span><span class="nc">line</span><span class="p">:</span><span class="nd">hover</span><span class="p">::</span><span class="nd">before</span><span class="o">,</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">line</span><span class="p">:</span><span class="nd">focus</span><span class="p">::</span><span class="nd">before</span><span class="w"> </span><span class="p">{</span>
<span class="w">    </span><span class="k">width</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span>
<span class="w">    </span><span class="k">transition</span><span class="p">:</span><span class="w"> </span><span class="mf">.2</span><span class="kt">s</span><span class="w"> </span><span class="kc">all</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>Ce serait dommage de se priver de ce genre de petites choses ! Ca me fait expérimenter un peu, et puis c'est toujours amusant à voir. Bien sûr, dans un souci d'accessibilité, les animations se déclenchent aussi lorsqu'un élément est placé en [focus] et pas seulement au survol de la souris.</p>
<h1>☁️</h1>
<hr/>
<h1>Et voilà !</h1>
<h3>Vous voulez voir ce que ça donne en vrai ? C'est par là : 👉 <a href="https://nubla.io">https://nubla.io</a> 👈</h3>
<p>Et n'hésitez pas à faire un tour sur notre <a href="https://framaforms.org/outils-informatiques-1593440082">sondage</a> concernant vos usages e-mail, cloud et internet, et savoir si l'offre de Nubla pourrait vous intéresser !</p>
<p>J'espère que la lecture vous a plu !</p>
            </div>
        </content>
        <author>
            <name>Brunélie Lauret &lt;brunelie@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Dernières contributions à des logiciels libres par l&#39;équipe Yaal Coop (rentrée 2021)</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-rentree-2021" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-rentree-2021</id>
        <updated>2021-08-31T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/pytest-dev/pytest">pytest</a></h1>
<p><em>Outil de tests unitaires en Python</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest/pull/8752">Personnalisation des thèmes de la coloration syntaxique</a></li>
</ul>
<h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Composant svelte de suggestion d'éléments dans une liste déroulante</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/94">Installation d'une suite de tests unitaires</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/95">Ignorer les accents lors de la surbrillance</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/74">Préchargement de la liste lorsque le composant est initialisé avec une valeur</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/70">Le contenu peut-être figé</a></li>
<li>Diverses maintenances <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/100">#100</a>
<a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/92">#92</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/83">#83</a>
<a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/77">#77</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/76">#76</a>
<a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/75">#75</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/72">#72</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/69">#69</a></li>
</ul>
<h1><a href="https://github.com/nhn/tui.editor/">toast-ui editor</a></h1>
<p><em>Éditeur markdown wysiwyg en Javascript</em></p>
<ul>
<li><a href="https://github.com/nhn/tui.editor/pull/1772">Attribut 'autofocus' qui permet au composant de ne pas prendre le focus au chargement d'une page</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/6">Ajout, édition et suppression des groupes d'utilisateurs</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/sheraf">sheraf</a></h1>
<p><em>Surcouche objet à ZODB</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/21">Décorateur sur les attributs sheraf pour personnaliser les fonctions de recherche et d'indexation</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/18">Utilitaires pour vérifier l'état de l'indexation d'une instance d'un modèle</a></li>
</ul>
<h1><a href="https://github.com/zopefoundation/ZEO">ZEO</a></h1>
<p><em>Serveur de base de données pour ZODB</em></p>
<ul>
<li><a href="https://github.com/zopefoundation/ZEO/pull/183">Correction dans la documentation d'un paramètre</a></li>
</ul>
<h1><a href="https://github.com/leapfrogonline/rstr">rstr</a></h1>
<p><em>Bibliothèque Python produisant des chaînes de caractères aléatoire</em></p>
<ul>
<li>Mises à jour du paquet (<a href="https://github.com/leapfrogonline/rstr/pull/6">métadonnées</a>, <a href="https://github.com/leapfrogonline/rstr/pull/9">versions de python</a>), une <a href="https://github.com/leapfrogonline/rstr/pull/7">vérification de paramètres passées</a>. L'ensemble est disponible dans la version 2.0 sur <a href="https://pypi.org/project/rstr/">pypi.org</a>.</li>
</ul>
<h1><a href="https://pygments.org/">Pygments</a></h1>
<p><em>Bibliothèque Python de coloration syntaxique</em></p>
<ul>
<li>Ajout d'un lexeur à <a href="https://github.com/pygments/pygments/pull/1808">Pygments</a> pour le format <a href="https://devcenter.heroku.com/articles/procfile#procfile-format">Procfile</a>. Les fichiers Procfile sont utilisés par des hébergeurs comme Heroku mais ils servent aussi pour des développements locaux (avec Foreman ou Honcho).</li>
</ul>
<h1><a href="https://python.org">Python.org</a></h1>
<ul>
<li>Correction d'un exemple de code sur le site <a href="https://github.com/python/pythondotorg/pull/1763">python.org</a>. La correction est intégrée dans le dépôt, mais pas encore disponible sur le site.</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Last FOSS contributions from the Yaal Coop team (summer 2021)</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-rentree-2021" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-rentree-2021</id>
        <updated>2021-08-31T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/pytest-dev/pytest">pytest</a></h1>
<p><em>The pytest framework makes it easy to write small tests, yet scales to support complex functional testing</em></p>
<ul>
<li><a href="https://github.com/pytest-dev/pytest/pull/8752">Syntax highlighting theme customization</a></li>
</ul>
<h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Simple Autocomplete / typeahead component for Svelte</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/94">Unit tests suite</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/95">Words highlighting ignore accents</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/74">async: Loads item list on focus when the component is pre-initialized</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/70">Lockable input</a></li>
<li>Janitoring <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/100">#100</a>
<a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/92">#92</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/83">#83</a>
<a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/77">#77</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/76">#76</a>
<a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/75">#75</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/72">#72</a> <a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/69">#69</a></li>
</ul>
<h1><a href="https://github.com/nhn/tui.editor/">toast-ui editor</a></h1>
<p><em>Markdown WYSIWYG Editor</em></p>
<ul>
<li><a href="https://github.com/nhn/tui.editor/pull/1772">add an 'autofocus' option that can disable initial focus</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/6">Group management</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/sheraf">sheraf</a></h1>
<p><em>A versatile ZODB abstraction layer</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/21">Attribute decorators</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/18">Indexation helpers</a></li>
</ul>
<h1><a href="https://github.com/zopefoundation/ZEO">ZEO</a></h1>
<p><em>ZODB Client-Server framework</em></p>
<ul>
<li><a href="https://github.com/zopefoundation/ZEO/pull/183">Replaced 'cache-size-bytes' with 'cache-size' in the documentation</a></li>
</ul>
<h1><a href="https://github.com/leapfrogonline/rstr">rstr</a></h1>
<p><em>rstr is a helper module for easily generating random strings of various types.</em></p>
<ul>
<li>Package updates (<a href="https://github.com/leapfrogonline/rstr/pull/6">metadata</a>, <a href="https://github.com/leapfrogonline/rstr/pull/9">python versions</a>), <a href="https://github.com/leapfrogonline/rstr/pull/7">parameters check</a>.</li>
</ul>
<h1><a href="https://pygments.org/">Pygments</a></h1>
<p><em>Pygments is a generic syntax highlighter written in Python</em></p>
<ul>
<li><a href="https://github.com/pygments/pygments/pull/1808">Procfile lexer</a></li>
</ul>
<h1><a href="https://python.org">Python.org</a></h1>
<ul>
<li><a href="https://github.com/python/pythondotorg/pull/1763">Code sample fix</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Manifeste agile et confinement - une rétrospective</title>
        <link href="https://dmerej.info/blog/fr/post/agile-et-confinement/" />
        <id>https://dmerej.info/blog/fr/post/agile-et-confinement/</id>
        <updated>2021-07-12T10:30:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1 id="introduction---retour-sur-le-manifeste-agile">Introduction - retour sur le manifeste agile <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#introduction---retour-sur-le-manifeste-agile">#</a></h1>
<p>Relisons-le ensemble, il est là:</p>
<p>=&gt; <a href="https://agilemanifesto.org/iso/fr/manifesto.html">https://agilemanifesto.org/iso/fr/manifesto.html</a></p>
<blockquote>
<p>Manifeste pour le développement Agile de logiciels</p>
</blockquote>
<blockquote>
<p>Nous découvrons comment mieux développer des logiciels par la pratique
et en aidant les autres à le faire. Ces expériences nous ont amenés à
valoriser :</p>
<p>Les individus et leurs interactions plus que les processus et les outils
Des logiciels opérationnels plus qu’une documentation exhaustive
La collaboration avec les clients plus que la négociation contractuelle
L’adaptation au changement plus que le suivi d’un plan</p>
<p>Nous reconnaissons la valeur des seconds éléments, mais privilégions les premiers.</p>
</blockquote>
<p>Notez que la comparaison “les individus et les interactions plus que processus et les outils” est en premier.</p>
<p>Comme le reste de l’article s’appuie sur ce concept je vous propose de le nommer “Principe d’Humanité” ci-dessous pour plus de lisibilité.</p>
<p>D’un autre côté “réagir au changement plus que suivre un plan” est en dernier et c’est pourtant la phrase qui donne son titre au manifeste - l’adjectif “agile” a été choisi pour s’y référer. Par conséquent, c’est la partie “réagir au changement” que l’on retient le plus, alors que le Principe d’Humanité est beaucoup moins connu.</p>
<p>Explorons ensemble ce paradoxe, en se replongeant dans l’effet du confinement en entreprise.</p>
<h1 id="ce-quétait-le-confinement">Ce qu’était le confinement <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#ce-qu%c3%a9tait-le-confinement">#</a></h1>
<h2 id="le-confinement-au-niveau-des-individus">Le confinement au niveau des individus <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#le-confinement-au-niveau-des-individus">#</a></h2>
<p>Du jour au lendemain, tous les salariés de la société ont été obligés de travailler depuis leur domicile. Les réactions de chaque personne ont été très différentes, entre :</p>
<p>Celles qui préfèrent tout simplement ne plus avoir à venir au bureau - pour un tas de raisons diverses (temps de trajet, peur de contaminer des proches, envie de passer du temps avec ses enfants, etc …)</p>
<p>Celles qui tolèrent mal le confinement - également pour des raisons diverses (besoin de socialiser avec les autres salariés, pas les bonnes conditions matérielles chez elles, etc …)</p>
<p>Celles qui ne le tolèrent pas du tout et cessent de travailler (cela peut aller de la simple perte de motivation en passant par la démission ou la dépression nerveuse)</p>
<p>Sans oublier les personnes qui pratiquaient le télétravail depuis déjà longtemps, ou celles qui ont simplement changé d’emploi</p>
<p>Nous voyons ici que la bonne façon d’aborder le problème du confinement doit nécessairement prendre en compte les individus au sens fort - c’est-à-dire pas seulement les personnes une par une, mais des personne singulières - dotées de personnalités propres.</p>
<h2 id="le-confinement-au-niveau-des-interactions-entre-individus">Le confinement au niveau des interactions entre individus <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#le-confinement-au-niveau-des-interactions-entre-individus">#</a></h2>
<p>D’un autre côté, les <em>conditions matérielles</em> des interactions entre individus ont radicalement changé.</p>
<p>Prenons par exemple le cas d’une conversation entre deux personnes (je laisse de côté
les réunions à plusieurs qui mériteraient un article à part).</p>
<p>Voici une liste non-exhaustive des différentes façons dont une conversation de travail peut avoir lieu si les deux collègues sont face à face :</p>
<ul>
<li>de part à et d’autre d’un bureau pour un conversation “officielle”</li>
<li>entre deux portes - par exemple juste avant ou juste après une réunion</li>
<li>autour de la machine à café  pour parler de la météo</li>
<li>autour d’un verre dans un bar en fin d’après-midi pour décompresser après le boulot</li>
<li>à la table d’un restaurant le midi pour une réunion commerciale</li>
<li>etc.</li>
</ul>
<p>Voici une liste exhaustive des différentes façons dont une conversation peut avoir lieu si les deux personnes ne sont /pas/ face à face :</p>
<ul>
<li>voix seulement (téléphone)</li>
<li>texte seulement (SMS ou messagerie instantanée)</li>
<li>vidéo-conférence (audio et vidéo - avec messagerie instantanée incluse ou non)</li>
</ul>
<p>Et c’est à peu près tout ce que la technique permet aujourd’hui - qu’on le veuille ou non !</p>
<p>Ainsi, la question posée par le confinement en entreprise peut être formulée ainsi : comment reproduire toute la richesse permise par les discussions face à face ?</p>
<p>Notez que cette question n’est ni problème technique, ni un problème financier, ni un problème de processus, mais bien d’interactions entre individus …</p>
<h1 id="limpact-du-confinement-sur-une-entreprise-fonctionnant-sans-le-principe-dhumanité">L’impact du confinement sur une entreprise fonctionnant sans le Principe d’Humanité <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#limpact-du-confinement-sur-une-entreprise-fonctionnant-sans-le-principe-dhumanit%c3%a9">#</a></h1>
<p>La thèse que je veux défendre est celle-ci : si l’entreprise dans son ensemble a oublié l’importance des individus et de leurs interactions, elle n’a aucun bon moyen de gérer correctement la question du confinement !</p>
<p>De fait, elle va naturellement ignorer le problème principal et s’occuper à la place des problèmes qu’elle sait déjà gérer, c’est à dire les problèmes pour lesquels il existe <em>déjà</em> un processus.</p>
<p>Par exemple la perte de clients, les problèmes d’approvisionnement etc. liés au confinement sont des soucis financiers ou logistiques pour lesquelles les solutions sont connues.</p>
<p>Au final, les problèmes liés <em>véritablement</em> au confinement vont être perçus comme des problèmes “d’organisation du travail”.</p>
<p>Ainsi, en supposant que l’entreprise survive, elle risque de prendre des décisions qui n’adressent pas vraiment la question, comme “mettre en place un nouveau processus de travail” (phrase floue si l’en est) - en s’inspirant de processus déjà existants comme SAfe, SCRUM, ou OKR pour ne citer que les plus connus.</p>
<p>À l’extrême, l’entreprise va économiser sur le prix de l’immobilier en optant pour des locaux plus petits (ou pas de locaux du tout) et compenser de la sorte le manque de productivité de la “masse salariale” …</p>
<h1 id="limpact-du-confinement-sur-une-organisation-fonctionnant-suivant-le-principe-dhumanité">L’impact du confinement sur une organisation fonctionnant suivant le Principe d’Humanité <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#limpact-du-confinement-sur-une-organisation-fonctionnant-suivant-le-principe-dhumanit%c3%a9">#</a></h1>
<p>La question posée par le confinement reste compliquée, bien sûr, mais au moins ce n’est pas un problème différent en nature de ceux que l’organisation sait <em>déjà</em> traiter.</p>
<p>Et en tout cas, une entreprise suivant le Principe d’Humanité aura de bien meilleures chances de gérer correctement la <em>fin</em> du confinement.</p>
<h1 id="conclusion-et-retour-sur-lagilité-en-entreprise">Conclusion et retour sur l’agilité en entreprise <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusion-et-retour-sur-lagilit%c3%a9-en-entreprise">#</a></h1>
<p>Réduire la question du confinement à “il faut trouver un moyen technique de travailler à distance”, et simplement investir dans la visioconférence et des outils collaboratifs en ligne, est, je pense, manquer l’essentiel.</p>
<p>Au passage, c’est aussi ignorer que l’Humanité a déjà connu dans l’histoire des conditions similaires au confinement - typiquement, un couvre-feu pendant la guerre.</p>
<p>J’espère vous avoir convaincu maintenant que le dernier principe agile (réagir au changement) découle en fait du premier.</p>
<p>En effet, les entreprises qui valorisaient les individus et leurs interactions par-dessus le le reste ont probablement pu réagir au changement qu’était le confinement bien mieux que les autres sans nécessairement avoir besoin de faire de plan - ce qui de toutes façons était très compliqué (souvenez-vous de votre propre état mental lors du premier confinement).</p>
<p>En réalité, les entreprises qui ont oublié le Principe d’Humanité sont finalement fort peu capables de réagir à des changements non prévus et sont finalement … peu agiles.</p>
<p>D’ailleurs, la seule chose qui ne changera probablement jamais dans une entreprise, c’est que c’est un ensemble complexe et mouvant d’individus et d’interactions …</p>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>Last FOSS contributions from the Yaal Coop team (spring 2021)</title>
        <link href="https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-mi-2021" />
        <id>https://yaal.coop/blog/en/dernieres-contributions-logiciels-libres-mi-2021</id>
        <updated>2021-06-09T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Simple Autocomplete / typeahead component for Svelte</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/35"><em>autocomplete</em> html5 flag</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/43">Delay between requests</a> (afin de ne pas surcharger le serveur)</li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/44">Ignore the old late responses</a> (afin de ne pas afficher de vieux résultats)</li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/46">List items customization</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/50">Activity indicator</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/54">Async generator support</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/58">Suggestions ignore diacritics</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/59">Submit enter by pressing Enter</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/68">Sort results by pertinence</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Simplistic OpenID Connect provider over OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/5">Groups support</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/sheraf">sheraf</a></h1>
<p><em>A versatile ZODB abstraction layer</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/16">Attribute hooks</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/15">Values method can index single values</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/14">Better QuerySet performances</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/13">Enum attribute</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/12">Attribute shared indexes</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/11">Indexes alternate definitions</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/10">raise exception if ModelAttribute is called without Model</a></li>
</ul>
<h1><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h1>
<p><em>Controls a slapd process in a pythonic way</em></p>
<ul>
<li>Project creation and publication.</li>
</ul>
<h1>cpython</h1>
<ul>
<li><a href="https://github.com/python/cpython/pull/24864">pprint.pprint function displays integer with underscores</a></li>
<li><a href="https://github.com/python/cpython/pull/23872">Change URL for 'from' link when used in a raised exception</a></li>
<li><a href="https://github.com/python/pythondotorg/pull/1763">fix input-output order in interpreter example</a></li>
</ul>
<h1><a href="https://github.com/wtforms/wtforms">wtforms</a></h1>
<p><em>A flexible forms validation and rendering library for Python.</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/689">New logo</a></li>
</ul>
<h1>Debian</h1>
<ul>
<li><a href="https://salsa.debian.org/ddp-team/release-notes/-/merge_requests/103">Improved publication notes</a></li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Dernières contributions à des logiciels libres par l&#39;équipe Yaal Coop</title>
        <link href="https://yaal.coop/blog/dernieres-contributions-logiciels-libres-mi-2021" />
        <id>https://yaal.coop/blog/dernieres-contributions-logiciels-libres-mi-2021</id>
        <updated>2021-06-09T23:00:00Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1><a href="https://github.com/pstanoev/simple-svelte-autocomplete">simple-svelte-autocomplete</a></h1>
<p><em>Composant svelte de suggestion d'éléments dans une liste déroulante</em></p>
<ul>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/35">Flag html5 <em>autocomplete</em></a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/43">Délai entre les requêtes</a> (afin de ne pas surcharger le serveur)</li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/44">Ignorer les vieilles réponses qui arrivent trop tard</a> (afin de ne pas afficher de vieux résultats)</li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/46">Personnalisation des éléments de la liste</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/50">Indicateur d'activité</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/54">Support des générateurs asynchrones</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/58">Ignorer les accents pour suggérer des éléments</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/59">Soumettre le formulaire en appuyant sur la touche Entrée</a></li>
<li><a href="https://github.com/pstanoev/simple-svelte-autocomplete/pull/68">Trier les résultats en fonction de leur pertinence</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/canaille">canaille</a></h1>
<p><em>Serveur OpenID Connect simpliste, basé sur OpenLDAP</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/canaille/-/merge_requests/5">Gestion des groupes d'utilisateurs</a></li>
</ul>
<h1><a href="https://gitlab.com/yaal/sheraf">sheraf</a></h1>
<p><em>Surcouche objet à ZODB</em></p>
<ul>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/16">Possibilité d'enregistrer des crochets à la création, l'édition ou la suppression d'attributs</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/15">Les méthodes d'indexation des indexes peuvent ne retourner qu'une unique valeur</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/14">De meilleures performances pour les QuerySet</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/13">Attribut Enum</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/12">Indexes partagés entre différents attributs</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/11">Plusieurs manières de définir des indexes</a></li>
<li><a href="https://gitlab.com/yaal/sheraf/-/merge_requests/10">Levée d'une erreur lorsqu'un ModelAttribute n'est pas appelé avec un Model</a></li>
</ul>
<h1><a href="https://github.com/python-ldap/python-slapd">python-slapd</a></h1>
<p><em>Bibliothèque python pour contrôler un server OpenLDAP</em></p>
<ul>
<li>Création et publication du projet.</li>
</ul>
<h1>cpython</h1>
<ul>
<li>pprint.pprint() dispose d'un <a href="https://github.com/python/cpython/pull/24864">paramètre underscore_numbers</a> qui améliore la lisibilité des gros entiers (sera disponible dans la prochaine version)</li>
<li><a href="https://github.com/python/cpython/pull/23872">Correction de liens internes dans la documentation</a> (rétroporté vers les versions 3.8 et 3.9)</li>
<li><a href="https://github.com/python/pythondotorg/pull/1763">Correction d'un exemple de code sur le site web</a></li>
</ul>
<h1><a href="https://github.com/wtforms/wtforms">wtforms</a></h1>
<p><em>Bibliothèque python de gestion de formulaires web</em></p>
<ul>
<li><a href="https://github.com/wtforms/wtforms/pull/689">Nouveau logo</a></li>
</ul>
<h1>Debian</h1>
<ul>
<li>modernisation d'icônes pour les <a href="https://salsa.debian.org/ddp-team/release-notes/-/merge_requests/103">notes de publication</a> (permet une cohérence graphique avec la mise-à-jour du <a href="https://salsa.debian.org/installer-team/installation-guide/-/merge_requests/11">guide d'installation</a>)</li>
</ul>
            </div>
        </content>
        <author>
            <name>Éloi Rivard &lt;eloi@yaal.coop&gt;</name>
        </author>
    </entry>
    <entry>
        <title>Python : compiler et faire tourner plusieurs versions sans collisions</title>
        <link href="https://www.olivierpons.fr/2021/05/21/python-compiler-et-faire-tourner-plusieurs-versions-sans-collisions/" />
        <id>https://www.olivierpons.fr/2021/05/21/python-compiler-et-faire-tourner-plusieurs-versions-sans-collisions/</id>
        <updated>2021-05-21T16:17:57Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Il faut aller chercher le code source qui vous intéresse.</p>
<p>Exemple, faire tourner un « vieux » Python 3.6, aller <a href="https://www.python.org/downloads/" rel="noopener" target="_blank">dans les versions ici</a> et prendre celle qui nous intéresse.</p>
<p>Puis récupérer le code source et le compiler :</p>
<pre>mkdir ~/source ; cd ~/source
wget https://www.python.org/ftp/python/3.6.13/Python-3.6.13.tar.xz
tar xvf Python-3.6.13.tar.xz
cd ~/source/Python-3.6.13
./configure &amp;&amp; make
sudo make altinstall</pre>
<p>Et voilà :</p>
<pre>~/source/Python-3.6.13$ python3.6
Python 3.6.13 (default, May 21 2021, 17:12:12) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt;</pre>
            </div>
        </content>
        <author>
            <name>Olivier Pons</name>
        </author>
    </entry>
    <entry>
        <title>Reconnaissance de chiffres manuscrits</title>
        <link href="https://zestedesavoir.com/articles/3655/reconnaissance-de-chiffres-manuscrits/" />
        <id>https://zestedesavoir.com/articles/3655/reconnaissance-de-chiffres-manuscrits/</id>
        <updated>2021-01-31T02:43:10Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Une méthode simple pour reconnaitre des chiffres manuscrits avec OpenCV
            </div>
        </content>
        <author>
            <name>thibsc</name>
        </author>
    </entry>
    <entry>
        <title>Une page se tourne</title>
        <link href="https://dmerej.info/blog/fr/post/une-page-se-tourne/" />
        <id>https://dmerej.info/blog/fr/post/une-page-se-tourne/</id>
        <updated>2021-01-18T15:20:55Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1 id="une-page-se-tourne-">Une page se tourne … <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#une-page-se-tourne-">#</a></h1>
<p>Vendredi dernier j’ai signé une rupture conventionnelle qui mettra fin
au contrat qui me lie à <a href="https://tanker.io">Tanker</a> le 24 février 2021.</p>
<p>Ainsi se conclura une aventure de près de 5 années riches en
enseignements et en rebondissements. Merci à tous mes collègues, et bon
courage pour la suite!</p>
<h1 id="et-ensuite-">Et ensuite ? <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#et-ensuite-">#</a></h1>
<p>Plusieurs possibilités s’ouvrent à moi.</p>
<p>Dans l’idéal, j’aimerais trouver une activité de professeur à temps
plein (toujours dans le domaine de l’informatique) et dans la région
parisienne, mais je suis ouvert à toute forme de contrat.</p>
<p>J’ai acquis de nombreuses compétences en tant que développeur
professionnel - tant chez Tanker que dans ma dans ma boîte précédente,
Softbank Robotics - compétences que je souhaite aujourd’hui transmettre.</p>
<p>Parmi les sujets sur lesquels je me sens prêt à donner des cours dès
maintenant:</p>
<ul>
<li>Le langage de programmation Python (Voir: <a href="https://dmerej.info/python/">https://dmerej.info/python/</a>)</li>
<li>Les bonnes pratiques de développement (tests automatiques, intégration
continue, DevOps, revue de code, …)</li>
<li>Les méthodes agiles (SCRUM et Lean en particulier)</li>
<li>etc …</li>
</ul>
<p>Il est bien sûr possible que je n’arrive pas à trouver un poste à temps
plein tout de suite, et donc j’ai prévu de chercher également un poste
dans une coopérative ou similaire.</p>
<p>Je ne me vois pas du tout travailler dans une société de service ou dans
une grosse boîte, et après plus de 10 ans passés dans le monde des start-
up, j’ai besoin de changement.  Je pense que je m’épanouirai davantage
dans ce genre de structure, et en tout cas, cela m’intéresse de
découvrir une nouvelle forme d’organisation.</p>
<h1 id="une-invitation">Une invitation <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#une-invitation">#</a></h1>
<p>J’écris cet article en partie pour clarifier mes objectifs pour l’avenir,
mais surtout pour que vous, chers lecteurs, puissiez le partager et
m’aider à passer cette nouvelle étape de ma carrière.</p>
<p>Comme d’habitude, ma <a href="https://dmerej.info/blog/fr/pages/about/">page de contact</a> est là si vous
avez des pistes à me suggérer, des questions à me poser, ou pour toute autre
remarque.</p>
<p>À bientôt !</p>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>Sortie de Python 3.9</title>
        <link href="https://zestedesavoir.com/articles/3681/sortie-de-python-3-9/" />
        <id>https://zestedesavoir.com/articles/3681/sortie-de-python-3-9/</id>
        <updated>2020-10-05T09:31:11Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Tour d'horizon de la dernière version du célèbre langage de programmation
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Plongée au cœur de l&#39;asynchrone en Python</title>
        <link href="https://zestedesavoir.com/articles/3306/plongee-au-coeur-de-lasynchrone-en-python/" />
        <id>https://zestedesavoir.com/articles/3306/plongee-au-coeur-de-lasynchrone-en-python/</id>
        <updated>2020-04-15T06:59:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Sans boire la tasse
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Déployer une application Django en production</title>
        <link href="https://zestedesavoir.com/tutoriels/2213/deployer-une-application-django-en-production/" />
        <id>https://zestedesavoir.com/tutoriels/2213/deployer-une-application-django-en-production/</id>
        <updated>2020-03-09T20:32:31Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Déployer une application Django en production
            </div>
        </content>
        <author>
            <name>Anto59290</name>
        </author>
    </entry>
    <entry>
        <title>Variables, scopes et closures en Python</title>
        <link href="https://zestedesavoir.com/tutoriels/3163/variables-scopes-et-closures-en-python/" />
        <id>https://zestedesavoir.com/tutoriels/3163/variables-scopes-et-closures-en-python/</id>
        <updated>2019-07-23T17:59:50Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Comprendre leur fonctionnement et en éviter les pièges
            </div>
        </content>
        <author>
            <name>entwanne</name>
        </author>
    </entry>
    <entry>
        <title>Écriture de tests en Python: pytest et TDD</title>
        <link href="https://dmerej.info/blog/fr/post/tester-en-python-pytest-et-tdd/" />
        <id>https://dmerej.info/blog/fr/post/tester-en-python-pytest-et-tdd/</id>
        <updated>2019-06-01T18:21:28Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Note : cet article reprend en grande partie le cours donné à <a href="https://e2li.org">l’École
du Logiciel Libre</a> le 18 mai 2019.
Il s’inspire également des travaux de Robert C. Martin (alias Uncle Bob) sur la question,
notamment sa série de vidéos sur
<a href="https://cleancoders.com/videos/clean-code">cleancoders.com</a> <sup id="fnref:1"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:1">1</a></sup></p>
<h1 id="assertions">Assertions <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#assertions">#</a></h1>
<p>En guise d’introduction, penchons-nous un peu sur le mot-clé <code>assert</code>.</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">faire_le_café</span>(au_régime=<span style="color: #6ab825; font-weight: bold;">False</span>, sucre=<span style="color: #6ab825; font-weight: bold;">True</span>):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">if</span> au_régime:
</span></span><span style="display: flex;"><span>         <span style="color: #6ab825; font-weight: bold;">assert</span> <span style="color: #6ab825; font-weight: bold;">not</span> sucre
</span></span></code></pre></div><p>Que se passe-t-il lorsque ce code tourne avec <code>au_régime</code> à <code>True</code> et <code>sucre</code> à <code>True</code> ?</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>&gt;&gt;&gt; faire_le_café(au_régime=<span style="color: #6ab825; font-weight: bold;">True</span>, sucre=<span style="color: #6ab825; font-weight: bold;">True</span>)
</span></span><span style="display: flex;"><span>Traceback (most recent call last):
</span></span><span style="display: flex;"><span>  File <span style="color: #ed9d13;">"foo.py"</span>, line <span style="color: #3677a9;">7</span>, <span style="color: #6ab825; font-weight: bold;">in</span> &lt;module&gt;
</span></span><span style="display: flex;"><span>    faire_le_café()
</span></span><span style="display: flex;"><span>  File <span style="color: #ed9d13;">"foo.py"</span>, line <span style="color: #3677a9;">5</span>, <span style="color: #6ab825; font-weight: bold;">in</span> faire_le_café
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> <span style="color: #6ab825; font-weight: bold;">not</span> sucre
</span></span><span style="display: flex;"><span><span style="color: #bbb;">AssertionError</span>
</span></span></code></pre></div><p>On constate que <code>assert</code> a évalué la condition et comme celle-ci était “falsy”, il a levé une exception nommée <code>AssertionError</code></p>
<p>On peut modifier le message de l’assertion en rajoutant une chaîne de caractères après la virgule :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">faire_le_café</span>(au_régime=<span style="color: #6ab825; font-weight: bold;">False</span>, sucre=<span style="color: #6ab825; font-weight: bold;">True</span>):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">if</span> au_régime:
</span></span><span style="display: flex;"><span>         <span style="color: #6ab825; font-weight: bold;">assert</span> <span style="color: #6ab825; font-weight: bold;">not</span> sucre, <span style="color: #ed9d13;">"tu es au régime: pas de sucre dans le café!"</span>
</span></span></code></pre></div><p>Et on peut aussi vérifier que <code>assert</code> ne fait rien si la condition est “truthy” :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>&gt;&gt;&gt; x = <span style="color: #3677a9;">42</span>
</span></span><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #6ab825; font-weight: bold;">assert</span> x
</span></span><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># rien</span>
</span></span></code></pre></div><h1 id="à-quoi-servent-les-assertions">À quoi servent les assertions <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#%c3%a0-quoi-servent-les-assertions">#</a></h1>
<p>Comme on l’a vu, utiliser <code>assert</code> ressemble fortement à lever une exception. Dans les deux cas, on veut signaler
à celui qui appelle notre code que quelque chose ne va pas. Mais <code>assert</code> est différent par deux aspects :</p>
<ul>
<li>Il peut arrive que la ligne contenant <code>assert</code> soit tout simplement ignorée <sup id="fnref:2"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:2">2</a></sup>.</li>
<li><code>assert</code> et souvent utilisé pour signaler qu’il y a une erreur <em>dans le code</em> qui a appelé la fonction, et
non à cause d’une erreur “extérieure”</li>
</ul>
<p>Voir <a href="http://sametmax.com/programmation-par-contrat-avec-assert/">cet article de Sam &amp; Max</a> pour plus de détails.</p>
<h1 id="quest-ce-quun-testnbsp">Qu’est-ce qu’un test ? <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#quest-ce-quun-testnbsp">#</a></h1>
<p>Voici un exemple minimal :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># dans calc.py</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_one</span>(x):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">2</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># dans test_calc.py</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">calc</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>result = calc.add_one(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">assert</span> result == <span style="color: #3677a9;">4</span>, <span style="color: #ed9d13;">"result != 4"</span>
</span></span></code></pre></div><p>On retrouve l’idée d’utiliser <code>assert</code> pour indiquer une erreur <em>interne</em> au code. En l’occurrence, si on lance le script <code>test_calc.py</code>, on va obtenir :</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ python3 test_calc.py
</span></span><span style="display: flex;"><span>Traceback (most recent call last):
</span></span><span style="display: flex;"><span>  File <span style="color: #ed9d13;">"test_calc.py"</span>, line 4, in &lt;module&gt;
</span></span><span style="display: flex;"><span>    assert <span style="color: #40ffff;">result</span> == 4, <span style="color: #ed9d13;">"result != 4"</span>
</span></span><span style="display: flex;"><span>AssertionError: result != <span style="color: #3677a9;">4</span>
</span></span></code></pre></div><p>Notez que le message d’erreur ne nous indique pas la <em>valeur effective</em> de <code>result</code>, juste sa <em>valeur attendue</em>.</p>
<p>Quoi qu’il en soit, le code dans <code>test_calc.py</code> nous a permis de trouver un bug dans la fonction <code>add_one</code> de  <code>calc.py</code></p>
<h1 id="code-de-test-et-code-de-production">Code de test et code de production <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#code-de-test-et-code-de-production">#</a></h1>
<p>On dit que <code>calc.py</code> est le code <em>de production</em>, et <code>test_calc.py</code> le code <em>de test</em>. Comme son nom l’indique, le code de production sert de base à un <em>produit</em> - un programme, un site web, etc.</p>
<p>On sépare souvent le code de production et le code de test dans des fichiers différents, tout simplement parce que le code de test ne sert pas directement aux utilisateurs du produit. Le code de test ne sert en général qu’aux <em>auteurs</em> du code.</p>
<h1 id="les-deux-valeurs-du-code">Les deux valeurs du code <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#les-deux-valeurs-du-code">#</a></h1>
<p>Une petite digression s’impose ici. Selon Robert C. Martin, le code possède une <em>valeur primaire</em> et une <em>valeur secondaire</em>.</p>
<ul>
<li>La valeur primaire est le <em>comportement</em> du code - ce que j’ai appelé le <em>produit</em> ci-dessus</li>
<li>La valeur secondaire est le fait que le code (et donc le produit) peut être <em>modifié</em>.</li>
</ul>
<p>Selon lui, la valeur secondaire (en dépit de son nom) est la plus importante : dans <code>software</code>, il y a “soft”, par opposition à <code>hardware</code>. Si vous avez un produit qui fonctionne bien mais que le code est impossible à changer, vous
risquez de vous faire de ne pas réussir à rajouter de nouvelles fonctionnalités,
de ne pas pouvoir corriger les bugs suffisamment rapidement, et de vous faire dépasser par la concurrence.</p>
<p>Ainsi, si le code de test n’a <em>a priori</em> pas d’effet sur la valeur <em>primaire</em> du code (après tout, l’utilisateur
du produit n’est en général même pas <em>conscient</em> de son existence), il a un effet très important sur la valeur <em>secondaire</em>, comme on le verra par la suite.</p>
<h1 id="pytest">pytest <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#pytest">#</a></h1>
<p>On a vu plus haut comment écrire du code de test “à la main” avec <code>assert</code>. Étoffons un peu l’exemple :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># dans calc.py</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_one</span>(x):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_two</span>(x):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">2</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># dans test_calc.py</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>result = calc.add_one(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">assert</span> result == <span style="color: #3677a9;">4</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>result = calc.add_two(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">assert</span> result == <span style="color: #3677a9;">7</span>
</span></span></code></pre></div><p>On constate que tester le code ainsi est fastidieux :</p>
<ul>
<li>Les valeurs effectives ne sont pas affichées par défaut</li>
<li>Le programme de test va s’arrêter à la première erreur, donc si <code>calc_one</code> est cassé, on ne saura rien sur l’état de <code>calc_two</code></li>
<li>On ne peut pas facilement isoler les tests à lancer</li>
</ul>
<p>C’est là que <code>pytest</code> entre en jeu.</p>
<p>On commence par créer un virtualenv pour <code>calc</code> et par installer <code>pytest</code> dedans <sup id="fnref:3"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:3">3</a></sup></p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ mkdir -p venvs &amp;&amp; <span style="color: #24909d;">cd</span> venvs
</span></span><span style="display: flex;"><span>$ python3 -m venv calc
</span></span><span style="display: flex;"><span>$ <span style="color: #24909d;">source</span> calc/bin/activate
</span></span><span style="display: flex;"><span>(calc) $ pip install pytest
</span></span></code></pre></div><p>Ensuite, on transforme chaque assertion en une fonction commençant par <code>test_</code> :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">calc</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_add_one</span>():
</span></span><span style="display: flex;"><span>    result = calc.add_one(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> result == <span style="color: #3677a9;">4</span>, <span style="color: #ed9d13;">"result != 4"</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_add_two</span>():
</span></span><span style="display: flex;"><span>    result = calc.add_two(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> result == <span style="color: #3677a9;">7</span>
</span></span></code></pre></div><p>… et on corrige les bugs :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_one</span>(x):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">1</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_two</span>(x):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">2</span>
</span></span></code></pre></div><p>Enfin, on lance <code>pytest</code> en précisant le chemin de fichier de test :</p>
<pre tabindex="0"><code>$ pytest test_calc.py
============================= test session starts ==============================
test_calc.py ..                                                          [100%]
========================== 2 passed in 0.01 seconds ===========================
</code></pre><p>Chaque point après <code>test_calc.py</code> représente un test qui passe. Voyons ce qui arrive si
on ré-introduit un bug :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_one</span>(x):
</span></span><span style="display: flex;"><span>     <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">3</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_two</span>(x):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">2</span>
</span></span></code></pre></div><pre tabindex="0"><code>$ pytest test_calc.py
============================= test session starts ==============================
test_calc.py F.                                                          [100%]

=================================== FAILURES ===================================
_________________________________ test_add_one _________________________________

    def test_add_one():
        result = calc.add_one(3)
&gt;       assert result == 4
E       assert 6 == 4

test_calc.py:5: AssertionError
</code></pre><p>À noter :</p>
<ul>
<li>Le test pour <code>add_two</code> a quand même été lancé</li>
<li>La valeur <em>effective</em> est affiché sous la ligne d’assert</li>
<li>La backtrace a été affiché</li>
<li>On a une vue du code qui a produit le bug</li>
<li>Le test qui a échoué est affiché avec un <code>F</code> majuscule</li>
</ul>
<p>On peut aussi dire à pytest de ne lancer <em>que les tests qui ont échoués</em> à la session précédente :</p>
<pre tabindex="0"><code>$ pytest test_calc.py --last-failed
run-last-failure: rerun previous 1 failure

test_calc.py
=================================== FAILURES ===================================
_________________________________ test_add_one _________________________________
</code></pre><p>Cool, non ?</p>
<h1 id="limites-des-tests">Limites des tests <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#limites-des-tests">#</a></h1>
<p>Avant de poursuivre, penchons-nous sur deux limitations importantes des tests.</p>
<p>Premièrement, les tests peuvent échouer même si le code de production est correct :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_add_one</span>():
</span></span><span style="display: flex;"><span>   result = add_one(<span style="color: #3677a9;">2</span>)
</span></span><span style="display: flex;"><span>   <span style="color: #6ab825; font-weight: bold;">assert</span> result == <span style="color: #3677a9;">4</span>
</span></span></code></pre></div><p>Ici on a un <em>faux négatif</em>. L’exemple peut vous faire sourire, mais c’est un problème plus
fréquent que ce que l’on croit.</p>
<p>Ensuite, les tests peuvent passer <em>en dépit</em> de bugs dans le code. Par exemple, si
on oublie une assertion :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">add_two</span>(x):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">return</span> x + <span style="color: #3677a9;">3</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_add_two</span>():
</span></span><span style="display: flex;"><span>    result = calc.add_two(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># fin du test</span>
</span></span></code></pre></div><p>Ici, on a juste vérifié qu’appeler <code>add_two(3)</code> ne provoque pas d’erreur. On dit
qu’on a un <em>faux positif</em>, ou un <em>bug silencieux</em>.</p>
<p>Autre exemple :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">fonction_complexe</span>():
</span></span><span style="display: flex;"><span>   <span style="color: #6ab825; font-weight: bold;">if</span> condition_a:
</span></span><span style="display: flex;"><span>       ...
</span></span><span style="display: flex;"><span>   <span style="color: #6ab825; font-weight: bold;">if</span> condition_b:
</span></span><span style="display: flex;"><span>      ...
</span></span></code></pre></div><p>Ici, même s’il n’y a que deux lignes commençant par <code>if</code>, pour être
exhaustif, il faut tester 4 possibilités, correspondant aux 4 valeurs
combinées des deux conditions. On comprend bien que plus le code devient
complexe, plus le nombre de cas à tester devient gigantesque.</p>
<p>Dans le même ordre d’idée, les tests ne pourront <em>jamais</em> vérifier le
comportement entier du code. On peut tester <code>add_one()</code> avec des exemples,
mais on voit difficilement commeent tester <code>add_one()</code> avec tous les entiers
possibles. <sup id="fnref:4"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:4">4</a></sup></p>
<p>Cela dit, maintenant qu’on sait comment écrire et lancer des tests,
revenons sur les bénéfices des tests sur la valeur secondaire du code.</p>
<h1 id="empêcher-les-régressions">Empêcher les régressions <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#emp%c3%aacher-les-r%c3%a9gressions">#</a></h1>
<p>On a vu comment les tests peuvent mettre en évidence des bugs présents dans le code.</p>
<p>Ainsi, à tout moment, on peut lancer la suite de tests pour vérifier (une partie) du
comportement du code, notamment après toute <em>modification</em> du code de production.</p>
<p>On a donc une chance de trouver des bugs bien avant que les utilisateurs du produit
l’aient entre les mains.</p>
<h1 id="refactorer-sans-peur">Refactorer sans peur <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#refactorer-sans-peur">#</a></h1>
<p>Le deuxième effet bénéfique est lié au premier.</p>
<p>Imaginez un code avec un comportement assez complexe. Vous avez une nouvelle fonctionnalité à
rajouter, mais le code dans son état actuel ne s’y prête pas.</p>
<p>Une des solutions est de commencer par effectuer un <em>refactoring</em>, c’est-à dire de commencer
par <em>adapter</em> le code mais <em>sans changer son comportement</em> (donc sans introduire de bugs). Une fois ce refactoring effectué,
le code sera prêt à être modifié et il deviendra facile d’ajouter la fonctionnalité.</p>
<p>Ainsi, disposer d’une batterie de tests qui vérifient le comportement du programme automatiquement et de manière exhaustive
est très utile. Si, à la fin du refactoring vous pouvez lancer les tests et constater qu’ils passent tous, vous serez plus confiant sur le fait que votre refactoring n’a pas introduit de nouveaux bugs.</p>
<h1 id="une-discipline">Une discipline <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#une-discipline">#</a></h1>
<p>Cela peut paraître surprenant, surtout à la lumière des exemples basiques que je vous ai montrés, mais écrire des tests est un art <em>difficile</em> à maîtriser. Cela demande un état d’esprit <em>différent</em>
de celui qu’on a quand on écrit du code de production. En fait, écrire des bons tests est une compétence
qui s’apprend.</p>
<p>Ce que je vous propose ici c’est une <em>discipline</em> : un ensemble de règles et une façon de faire qui vous
aidera à développer cette compétence. Plus vous pratiquerez cette discipline, meilleur sera votre code
de test, et, par extension, votre code de production.</p>
<p>Commençons par les règles :</p>
<ul>
<li>Règle 1 : Il est interdit d’écrire du code de production, <em>sauf</em> si c’est pour faire passer un test qui
a échoué.</li>
<li>Règle 2 : Il est interdit d’écrire plus de code que celui qui est nécessaire pour provoquer une erreur
dans les tests (n’importe quelle erreur)</li>
<li>Règle 3 : Il est interdit d’écrire plus de code que celui qui est nécessaire pour faire passer
un test qui a échoué</li>
<li>Règle 4 : Une fois que tous les tests passent, il est interdit de modifier le code sans s’arrêter
pour considérer la possibilité d’un refactoring. <sup id="fnref:5"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:5">5</a></sup></li>
</ul>
<p>Et voici une procédure pour appliquer ces règles: suivre le <em>cycle</em> de dévelopement suivant :</p>
<ul>
<li>Écrire un test qui échoue - étape “red”</li>
<li>Faire passer le test - étape “green”</li>
<li>Refactorer à la fois le code de production et le code de test - étape “refactor”</li>
<li>Retour à l’étape “red”.</li>
</ul>
<h1 id="tdd-en-pratique">TDD en pratique <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#tdd-en-pratique">#</a></h1>
<p>Si tout cela peut vous semble abstrait, je vous propose une démonstration.</p>
<p>Pour cela, on va utiliser les <a href="https://fr.wikipedia.org/wiki/Bowling#R%C3%A8gles">règles du bowling</a>.</p>
<p>Comme on code en anglais<sup id="fnref:6"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:6">6</a></sup>, on va utiliser les termes anglophones. Voici les règles :</p>
<ul>
<li>Un jeu de bowling comporte 10 carreaux (ou <em>frames</em>).</li>
<li>Chaque frame comporte deux lancers (ou <em>roll</em>) et 10 quilles (ou <em>pins</em>)</li>
<li>Si on renverse toutes les quilles en un lancer, on marque un abat (ou <em>strike</em>)</li>
<li>Si on renverse toutes les quilles dans un même carreau, on marque une réserve (ou <em>spare</em>)</li>
</ul>
<p>On calcule le score frame par frame :</p>
<ul>
<li>Si on fait un strike, on marque 10 points, plus les points obtenus à la frame suivante (donc 2 rolls)</li>
<li>Si on fait une spare, on marque 10 points, plus les points obtenus au lancer suivant (donc juste le roll suivant)</li>
<li>Sinon on marque le total de quilles renversées dans la frame</li>
</ul>
<p>La dernière frame est spéciale : si on fait un strike, on a droit à deux rolls supplémentaires, et si on fait une spare,
on a droit à un roll en plus.</p>
<h1 id="un-peu-darchitecture">Un peu d’architecture <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#un-peu-darchitecture">#</a></h1>
<p>La règle 0 de tout bon programmeur est : “réfléchir avant de coder”. Prenons le temps de réfléchir un peu, donc.</p>
<p>On peut se dire que pour calculer le score, une bonne façon sera d’avoir une classe <code>Game</code> avec deux méthodes:</p>
<ul>
<li><code>roll()</code>, qui sera appelée à chaque lancer avec le nombre de quilles renversées en paramètre</li>
<li><code>score()</code>, qui renverra le score final</li>
</ul>
<p>Au niveau du découpage en classes, on peut partir du diagramme suivant:</p>
<p><img alt="class diagram" src="https://dmerej.info/blog/pics/bowling.png"/></p>
<p>On a:</p>
<ul>
<li>Une classe <code>Game</code> qui contient des <code>frames</code></li>
<li>Chaque frame est une instance de la class <code>Frame</code></li>
<li>Chaque frame contient une ou deux instances de la class <code>Roll</code></li>
<li>Une classe <code>Roll</code> contenant un attribut <code>pins</code> correspondant au nombre
de quilles renversées.</li>
<li>Une classe <code>TenthFrame</code>, qui hérite de la classe <code>Frame</code> et implémente
les règles spécifiques au dernier lancer.</li>
</ul>
<h1 id="cest-parti">C’est parti <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#cest-parti">#</a></h1>
<p>Retours aux règles:</p>
<ul>
<li>Règle 1: Il est interdit d’écrire du code de production, <em>sauf</em> si c’est pour faire passer un test qui
a échoué.</li>
<li>Règle 2: Il est interdit d’écrire plus de code que celui qui est nécessaire pour provoquer une erreur
dans les tests (n’importe quelle erreur)</li>
<li>Règle 3: Il est interdit d’écrire plus de code que celui qui est nécessaire pour faire passer
un test qui a échoué</li>
<li>Règle 4: Une fois que tous les tests passent, il est interdit de modifier le code sans s’arrêter
pour considérer la possibilité d’un refactoring. <sup id="fnref1:5"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:5">5</a></sup></li>
</ul>
<p>Comme pour l’instant on a aucun code, la seule chose qu’on puisse faire c’est écrire un test qui échoue.</p>
<center>⁂ RED⁂</center>
<p>On crée un virtualenv pour notre code:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ python3 -m venvs/bowling
</span></span><span style="display: flex;"><span>$ <span style="color: #24909d;">source</span> venvs/bowling/bin/activate
</span></span><span style="display: flex;"><span>$ pip install pytest
</span></span></code></pre></div><p>On créé un fichier <code>test_bowling.py</code> qui contient <em>juste une ligne</em>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">bowling</span>
</span></span></code></pre></div><p>On lance les tests:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ pytest test_bowling.py
</span></span><span style="display: flex;"><span>test_bowling.py:1: in &lt;module&gt;
</span></span><span style="display: flex;"><span>    import bowling
</span></span><span style="display: flex;"><span>E   ModuleNotFoundError: No module named <span style="color: #ed9d13;">'bowling'</span>
</span></span></code></pre></div><p>On a une erreur, donc on arrête d’écrire du code de test (règle 2), et on passe
à l’état suivant.</p>
<center>⁂ GREEN⁂</center>
<p>Pour faire passer le test, il suffit de créer un fichier <code>bowling.py</code> vide.</p>
<pre tabindex="0"><code>$ pytest test_bowling.py
collected 0 items

========================= no tests ran in 0.34 seconds ========================
</code></pre><p>Bon, clairement ici il n’y a rien à refactorer (règle 4), donc on repart au début du cycle.</p>
<center>⁂ RED⁂</center>
<p>Ici on cherche à faire échouer le test le plus simplement possible.</p>
<p>Commençons simplement par vérifier qu’on peut instancier la class Game :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">bowling</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_can_create_game</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span></code></pre></div><pre tabindex="0"><code>$ pytest test_bowling.py
&gt;       game = bowling.Game()
E       AttributeError: module 'bowling' has no attribute 'Game'
</code></pre><p>Le test échoue, faisons-le passer :</p>
<center>⁂GREEN⁂</center>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">pass</span>
</span></span></code></pre></div><p>Toujours rien à refactorer …</p>
<center>⁂RED⁂</center>
<p>Écrivons un test pour <code>roll()</code> :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_can_roll</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">0</span>)
</span></span></code></pre></div><pre tabindex="0"><code>$ pytest test_bowling.py
&gt;       game.roll(0)
E       AttributeError: 'Game' object has no attribute 'roll'
</code></pre><center>⁂GREEN⁂</center>
<p>Faisons passer les tests en rajoutant une méthode :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">pass</span>
</span></span></code></pre></div><p>Toujours pas de refactoring en vue. En même temps, on n’a que 6 lignes de test
et 3 lignes de code de production …</p>
<center>⁂RED⁂</center>
<p>On continue à tester les méthodes de la classe Game, de la façon la plus simple possible :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_can_score</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span></code></pre></div><pre tabindex="0"><code>$ pytest test_bowling.py
&gt;       game.roll(0)
E       AttributeError: 'Game' object has no attribute 'roll'
</code></pre><center>⁂GREEN⁂</center>
<p>On fait passer le test, toujours de la façon la plus simple possible :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">pass</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>    	<span style="color: #6ab825; font-weight: bold;">pass</span>
</span></span></code></pre></div><center>⁂ REFACTOR⁂</center>
<p>Le code production a l’air impossible à refactorer, mais jetons un œil aux tests :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">bowling</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_can_create_game</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_can_roll</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_can_score</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    game.score()
</span></span></code></pre></div><p>Hum. Le premier et le deuxième test sont inclus <em>exactement</em> dans le dernier test. Ils ne servent donc à rien, et
peuvent être supprimés.</p>
<center>⁂RED⁂</center>
<p>En y réfléchissant, <code>can_score()</code> ne vérifie même pas la valeur de retour de <code>score()</code>. Écrivons un test légèrement différent :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_score_is_zero_after_gutter</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">0</span>
</span></span></code></pre></div><p><code>gutter</code> signifie “gouttière” en anglais et désigne un lancer qui finit dans la rigole (et donc ne renverse aucune quille)</p>
<pre tabindex="0"><code>$ pytest test_bowling.py
&gt;       assert score == 0
E       assert None == 0
</code></pre><center>⁂GREEN⁂</center>
<p>Faisons le passer :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">pass</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> <span style="color: #3677a9;">0</span>
</span></span></code></pre></div><p>Notez qu’on a fait passer le test en écrivant du code que l’on <em>sait</em> être incorrect. Mais la règle 3 nous interdit d’aller plus loin.</p>
<p>Vous pouvez voir cela comme une contrainte arbitraire (et c’en est est une), mais j’aimerais vous faire remarquer qu’on en a fait <em>spécifié</em>
l’API de la classe Game. Le test, bien qu’il ne fasse que quelques lignes,
nous indique l’existence des métode <code>roll()</code> et <code>score()</code>, les paramètres
qu’elles attendent et, à un certain point, la façon dont elles intéragissent</p>
<p>C’est une autre facette des tests: ils vous permettent de transformer une
spécification en code éxecutable. Ou, dit autrement, ils vous permettent
d’écrire des exemples d’utilisation de votre API <em>pendant que vous
l’implémentez</em>. Et, en vous forçant à ne pas écrire trop de code de production,
vous avez la possibilité de vous concentrer <em>uniquement</em> sur l’API de votre code,
sans vous soucier de l’implémentation.</p>
<p>Bon, on a enlevé plein de tests, du coup il n’y a encore plus grand-chose à refactorer,
passons au prochain.</p>
<center>⁂RED⁂</center>
<p>Rappelez-vous, on vient de dire que le code de <code>score()</code> est incorrect. La question devient donc : quel test pouvons-nous
écrire pour nous forcer à écrire un code un peu plus correct ?</p>
<p>Une possible idée est d’écrire un test pour un jeu où tous les lancers renversent exactement une quille :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_all_ones</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">20</span>):
</span></span><span style="display: flex;"><span>        game.roll(<span style="color: #3677a9;">1</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">20</span>
</span></span></code></pre></div><pre tabindex="0"><code>&gt;       assert score == 20
E       assert 0 == 20
</code></pre><center>⁂GREEN⁂</center>
<p>Ici la boucle dans le test nous force à <em>changer</em> l’état de la
class Game à chaque appel à <code>roll()</code>, ce que nous pouvons faire
en rajoutant un attribut qui compte le nombre de quilles
renversées.</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> __init__(self):
</span></span><span style="display: flex;"><span>        self.knocked_pins = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        self.knocked_pins += pins
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.knocked_pins
</span></span></code></pre></div><p>Les deux tests passent, mission accomplie.</p>
<center>⁂REFACTOR⁂</center>
<p>Encore une fois, concentrons-nous sur les tests.</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_score_is_zero_after_gutter</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_all_ones</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">20</span>):
</span></span><span style="display: flex;"><span>        game.roll(<span style="color: #3677a9;">1</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">20</span>
</span></span></code></pre></div><p>Les deux tests sont subtilement différents. Dans un cas, on appelle <code>roll()</code> une fois, suivi immédiatement d’un appel à <code>score()</code>.</p>
<p>Dans l’autre, on appelle <code>roll()</code> 20 fois, et on appelle <code>score()</code> à la fin.</p>
<p>Ceci nous montre une <em>ambiguïté</em> dans les spécifications. Veut-on pouvoir obtenir le score en temps réel, ou voulons-nous
simplement appeler <code>score</code> à la fin de la partie ?</p>
<p>On retrouve ce lien intéressant entre tests et API : aurions-nous découvert cette ambiguïté sans avoir écrit aucun test ?</p>
<p>Ici, on va décider que <code>score()</code> n’est appelé qu’à la fin de la partie, et donc réécrire les tests ainsi , en appelant 20 fois
<code>roll(0)</code>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_gutter_game</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">20</span>):
</span></span><span style="display: flex;"><span>        game.roll(<span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_all_ones</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">20</span>):
</span></span><span style="display: flex;"><span>        game.roll(<span style="color: #3677a9;">1</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">20</span>
</span></span></code></pre></div><p>Les tests continuent à passer. On peut maintenant réduire la duplication en introduisant une fonction <code>roll_many</code> :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_many</span>(game, count, value):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(count):
</span></span><span style="display: flex;"><span>        game.roll(value)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_gutter_game</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    roll_many(game, <span style="color: #3677a9;">20</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_all_ones</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    roll_many(game, <span style="color: #3677a9;">20</span>, <span style="color: #3677a9;">1</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">20</span>
</span></span></code></pre></div><center>⁂RED⁂</center>
<p>L’algorithme utilisé (rajouter les quilles renversées au score à chaque lancer) semble fonctionner tant qu’il n’y a ni spare ni strike.</p>
<p>Du coup, rajoutons un test sur les spares :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_one_spare</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">5</span>)  <span style="color: #999; font-style: italic;"># spare, next roll should be counted twice</span>
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    roll_many(game, <span style="color: #3677a9;">17</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">16</span>
</span></span></code></pre></div><pre tabindex="0"><code>        score = game.score()
&gt;       assert score == 16
E       assert 13 == 16
</code></pre><center>⁂GREEN⁂</center>
<p>Et là, on se retrouve <em>coincé</em>. Il semble impossible d’implémenter la gestion des spares sans revoir le code de production en profondeur :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        <span style="color: #999; font-style: italic;"># TODO: get the knocked pin in the next</span>
</span></span><span style="display: flex;"><span>        <span style="color: #999; font-style: italic;"># roll if we are in a spare ???</span>
</span></span><span style="display: flex;"><span>        self.knocked_pins += pins
</span></span></code></pre></div><p>C’est un état dans lequel on peut parfois se retrouver. La solution ? Faire un pas en arrière pour prendre du recul.</p>
<p>On peut commencer par désactiver le test qui nous ennuie :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">pytest</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #ffa500;">@pytest.mark.skip</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_one_spare</span>():
</span></span><span style="display: flex;"><span>   ...
</span></span></code></pre></div><p>Ensuite, on peut regarder le code de production dans le blanc des yeux :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        self.knocked_pins += pins
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.knocked_pins
</span></span></code></pre></div><p>Ce code a un problème : en fait, c’est la méthode <code>roll()</code> qui calcule le score, et non la fonction <code>score()</code> !</p>
<p>On comprend que <code>roll()</code> doit simplement enregistrer l’ensemble des résultats des lancers, et qu’ensuite seulement,
<code>score()</code> pourra parcourir les frames et calculer le score.</p>
<center>⁂REFACTOR⁂</center>
<p>On remplace donc l’attribut <code>knocked_pins()</code> par une liste de rolls et un index:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> __init__(self):
</span></span><span style="display: flex;"><span>        self.rolls = [<span style="color: #3677a9;">0</span>] * <span style="color: #3677a9;">21</span>
</span></span><span style="display: flex;"><span>        self.roll_index = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll</span>(self, pins):
</span></span><span style="display: flex;"><span>        self.rolls[self.roll_index] = pins
</span></span><span style="display: flex;"><span>        self.roll_index += <span style="color: #3677a9;">1</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        result = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> self.rolls:
</span></span><span style="display: flex;"><span>            result += roll
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> result
</span></span></code></pre></div><p>Petit aparté sur le nombre 21. Ici ce qu’on veut c’est le nombre maximum de frames.
On peut s’assurer que 21 est bien le nombre maximum en énumérant les cas possibles
de la dernière frame, et en supposant qu’il n’y a eu ni spare ni strike au cours
du début de partie (donc 20 lancers, 2 pour chacune des 10 premières frame)</p>
<ul>
<li>spare: on va avoir droit à un un lancer en plus: 20 + 1 = 21</li>
<li>strike: par définition, on n’a fait qu’un lancer à la dernière frame, donc au plus 19 lancers, et 19 plus 2 font bien 21.</li>
<li>sinon: pas de lancer supplémentaire, on reste à 20 lancers.</li>
</ul>
<p>Relançons les tests :</p>
<pre tabindex="0"><code>test_bowling.py ..s                                                      [100%]

===================== 2 passed, 1 skipped in 0.01 seconds ======================
</code></pre><p>(notez le ’s’ pour ‘skipped’)</p>
<p>L’algorithme est toujours éronné, mais on sent qu’on une meilleure chance de réussir à gérer les spares.</p>
<center>⁂RED⁂</center>
<p>On ré-active le test en enlevant la ligne <code>@pytest.mark.skip</code> et on retombe évidemment sur la même erreur :</p>
<pre tabindex="0"><code>&gt;       assert score == 16
E       assert 13 == 16
</code></pre><center>⁂GREEN⁂</center>
<p>Pour faire passer le test, on peut simplement itérer sur les frames une par une, en utilisant
une variable <code>i</code> qui vaut l’index du premier lancer de la prochaine frame :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        result = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        i = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> frame <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">10</span>):
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">if</span> self.rolls[i] + self.rolls[i + <span style="color: #3677a9;">1</span>] == <span style="color: #3677a9;">10</span>:  <span style="color: #999; font-style: italic;"># spare</span>
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">2</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">else</span>:
</span></span><span style="display: flex;"><span>                result += self.rolls[i]
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">1</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> result
</span></span></code></pre></div><p>Mon Dieu que c’est moche ! Mais cela me permet d’aborder un autre aspect du TDD. Ici, on est dans la phase “green”. On fait tout ce qu’on peut
pour faire passer le tests et rien d’autre. C’est un état d’esprit particulier, on était concentré sur l’algorithme en lui-même.</p>
<center>⁂REFACTOR⁂</center>
<p>Par contraste, ici on <em>sait</em> que l’algorithme est correct. Notre <em>unique</em> objectif est de rendre le code plus lisible. Un des avantages de TDD est qu’on passe d’un objectif précis à l’autre, au lieu d’essayer de tout faire en même temps.</p>
<p>Bref, une façon de refactorer est d’introduire une nouvelle méthode :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># note: i represents the index of the</span>
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># first roll of the current frame</span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">is_spare</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i] + self.rolls[i + <span style="color: #3677a9;">1</span>] == <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        result = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        i = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> frame <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">10</span>):
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">if</span> self.is_spare(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">2</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">else</span>:
</span></span><span style="display: flex;"><span>                result += self.rolls[i]
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">1</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span></code></pre></div><p>En passant, on s’est débarrassé du commentaire “# spare” à la fin du <code>if</code>, vu qu’il n’était plus utile. En revanche, on a gardé un commentaire au-dessus
de la méthode <code>is_spare()</code>. En effet, il n’est pas évident de comprendre la valeur représentée par l’index <code>i</code> juste en lisant le code. <sup id="fnref:7"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:7">7</a></sup></p>
<p>On voit aussi qu’on a gardé un peu de duplication. Ce n’est pas forcément très grave, surtout que l’algorithme est loin d’être terminé. Il faut encore gérer les strikes et la dernière frame.</p>
<p>Mais avant cela, revenons sur les tests (règle 4) :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_one_spare</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">5</span>)  <span style="color: #999; font-style: italic;"># spare, next roll should be counted twice</span>
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    roll_many(game, <span style="color: #3677a9;">17</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">16</span>
</span></span></code></pre></div><p>On a le même genre de commentaire qui nous suggère qu’il manque une abstraction quelque part : une fonction <code>roll_spare</code>.</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">bowling</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">pytest</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_many</span>(game, count, value):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(count):
</span></span><span style="display: flex;"><span>        game.roll(value)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_spare</span>(game):
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_one_spare</span>():
</span></span><span style="display: flex;"><span>    game = bowling.Game()
</span></span><span style="display: flex;"><span>    roll_spare(game)
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    roll_many(game, <span style="color: #3677a9;">17</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">16</span>
</span></span></code></pre></div><p>Les tests continuent à passer, tout va bien.</p>
<p>Mais le code de test peut <em>encore</em> être amélioré. On voit qu’on a deux fonctions qui prennent chacune le même paramètre en premier argument.</p>
<p>Souvent, c’est le signe qu’une classe se cache quelque part.</p>
<p>On peut créer une classe <code>GameTest</code> qui hérite de <code>Game</code> et contient les méthodes <code>roll_many()</code> et <code>roll_spare()</code> :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">bowling</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">pytest</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">GameTest</span>(bowling.Game):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_many</span>(self, count, value):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> roll <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(count):
</span></span><span style="display: flex;"><span>            self.roll(value)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_spare</span>(self):
</span></span><span style="display: flex;"><span>        self.roll(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>        self.roll(<span style="color: #3677a9;">5</span>)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_gutter_game</span>():
</span></span><span style="display: flex;"><span>    game = GameTest()
</span></span><span style="display: flex;"><span>    game.roll_many(<span style="color: #3677a9;">20</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_all_ones</span>():
</span></span><span style="display: flex;"><span>    game = bowling.GameTest()
</span></span><span style="display: flex;"><span>    game.roll_many(<span style="color: #3677a9;">20</span>, <span style="color: #3677a9;">1</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">20</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_one_spare</span>():
</span></span><span style="display: flex;"><span>    game = GameTest()
</span></span><span style="display: flex;"><span>    game.roll_spare()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    game.roll_many(<span style="color: #3677a9;">17</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">16</span>
</span></span></code></pre></div><p>Ouf! Suffisamment de refactoring pour l’instant, retour au rouge.</p>
<center>⁂RED⁂</center>
<p>Avec notre nouvelle classe définie au sein de <code>test_bowling.py</code> (on dit souvent “test helper”), on peut facilement rajouter le test sur les strikes :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">GameTest</span>:
</span></span><span style="display: flex;"><span>    ...
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_spare</span>(self):
</span></span><span style="display: flex;"><span>        ...
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">roll_strike</span>(self):
</span></span><span style="display: flex;"><span>        self.roll(<span style="color: #3677a9;">10</span>)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_one_strike</span>():
</span></span><span style="display: flex;"><span>    game = GameTest()
</span></span><span style="display: flex;"><span>    game.roll_strike()
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">3</span>)
</span></span><span style="display: flex;"><span>    game.roll(<span style="color: #3677a9;">4</span>)
</span></span><span style="display: flex;"><span>    game.roll_many(<span style="color: #3677a9;">16</span>, <span style="color: #3677a9;">0</span>)
</span></span><span style="display: flex;"><span>    score = game.score()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> score == <span style="color: #3677a9;">24</span>
</span></span></code></pre></div><p>A priori, tous les tests devraient passer sauf le dernier, et on devrait avoir une erreur de genre <code>x != 24</code>, avec x légèrement en-dessous de 24 :</p>
<pre tabindex="0"><code>________________________________ test_all_ones _________________________________

    def test_all_ones():
&gt;       game = bowling.GameTest()
E       AttributeError: module 'bowling' has no attribute 'GameTest'

_______________________________ test_one_strike ________________________________

    def test_one_strike():
        game = GameTest()
        game.roll_strike()
        game.roll(3)
        game.roll(4)
        game.roll_many(16, 0)
        score = game.score()
&gt;       assert score == 24
E       assert 17 == 24

test_bowling.py:48: AssertionError
</code></pre><p>Oups, deux erreurs ! Il se trouve qu’on a oublié de lancer les tests à la fin du dernier refactoring. En fait, il y a une ligne qui a été changée de façon incorrecte : <code> game = bowling.GameTest()</code> au lieu de <code>game = GameTest()</code>. L’aviez-vous remarqué ?</p>
<p>Cela illustre deux points :</p>
<ol>
<li>Il faut toujours avoir une vague idée des tests qui vont échouer et de quelle manière</li>
<li>Il est important de garder le cycle de TDD court. En effet, ici on <em>sait</em> que seuls les tests ont changé depuis la dernière session de test, donc on <em>sait</em> que le problème vient des tests et non du code de production.</li>
</ol>
<p>On peut maintenant corriger notre faux positif, relancer les tests, vérifier qu’ils échouent <em>pour la bonne raison</em> et passer à l’étape suivante.</p>
<pre tabindex="0"><code>______________________________ test_one_strike ________________________________

    def test_one_strike():
        game = GameTest()
        game.roll_strike()
        game.roll(3)
        game.roll(4)
        game.roll_many(16, 0)
        score = game.score()
&gt;       assert score == 24
E       assert 17 == 24

test_bowling.py:48: AssertionError
</code></pre><center>⁂GREEN⁂</center>
<p>Là encore, on a tous les éléments pour implémenter la gestion de strikes correctement, grâce aux refactorings précédents et au fait qu’on a implémenté l’algorithme de façon <em>incrémentale</em>, un petit bout à la fois.</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    ...
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">is_spare</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i] + self.rolls[i + <span style="color: #3677a9;">1</span>] == <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">is_strike</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i] == <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        result = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        i = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> frame <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">10</span>):
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">if</span> self.is_strike(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">1</span>]
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">2</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">1</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">elif</span> self.is_spare(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">2</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">else</span>:
</span></span><span style="display: flex;"><span>                result += self.rolls[i]
</span></span><span style="display: flex;"><span>                result += self.rolls[i + <span style="color: #3677a9;">1</span>]
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> result
</span></span></code></pre></div><p>J’espère que vous ressentez ce sentiment que le code “s’écrit tout seul”. Par contraste, rappelez-vous la difficulté pour implémenter les spares et imaginez à quel point cela aurait été difficile de gérer les spares <em>et</em> les strikes en un seul morceau !</p>
<center>⁂REFACTOR⁂</center>
<p>On a maintenant une boucle avec <em>trois</em> branches. Il est plus facile de finir le refactoring commencé précédement, et d’isoler les lignes qui se ressemblent des lignes qui diffèrent :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Game</span>:
</span></span><span style="display: flex;"><span>    ...
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">is_strike</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i] == <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">is_spare</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i] + self.rolls[i + <span style="color: #3677a9;">1</span>] == <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">next_two_rolls_for_strike</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i + <span style="color: #3677a9;">1</span>] + self.rolls[i + <span style="color: #3677a9;">2</span>]
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">next_roll_for_spare</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i + <span style="color: #3677a9;">2</span>]
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">rolls_in_frame</span>(self, i):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.rolls[i] + self.rolls[i + <span style="color: #3677a9;">1</span>]
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">score</span>(self):
</span></span><span style="display: flex;"><span>        result = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        i = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> frame <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">10</span>):
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">if</span> self.is_strike(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.next_two_rolls_for_strike(i)
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">1</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">elif</span> self.is_spare(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.next_roll_for_spare(i)
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">else</span>:
</span></span><span style="display: flex;"><span>                result += self.rolls_in_frame(i)
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> result
</span></span></code></pre></div><p>On approche du but, il ne reste plus qu’à gérer la dernière frame.</p>
<center>⁂RED⁂</center>
<p>Écrivons maintenant le test du jeu parfait, où le joueur fait un strike à chaque essai. Il y a donc 10 frames de strike, puis deux strikes (pour les deux derniers lancers de la dernière frame) soit 12 strikes en tout.</p>
<p>Et comme tout joueur de bowling le sait, le score maximum au bowling est 300 :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_perfect_game</span>():
</span></span><span style="display: flex;"><span>    game = GameTest()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">for</span> i <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">0</span>, <span style="color: #3677a9;">12</span>):
</span></span><span style="display: flex;"><span>        game.roll_strike()
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">assert</span> game.score() == <span style="color: #3677a9;">300</span>
</span></span></code></pre></div><p>On lance les tests, et…</p>
<pre tabindex="0"><code>collected 5 items

test_bowling.py .....                                                          [100%]
============================= 5 passed in 0.02 seconds ==============================
</code></pre><p>Ils passent ?</p>
<p>Ici, je vais vous laisser 5 minutes de réflexion pour vous convaincre qu’en realité, la dernière
frame n’a absolument rien de spécial, et que c’est la raison pour laquelle notre algorithme
fonctionne.</p>
<h1 id="conclusions">Conclusions <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusions">#</a></h1>
<p>D’abord, je trouve qu’on peut être fier du code auquel on a abouti :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>        result = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        i = <span style="color: #3677a9;">0</span>
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">for</span> frame <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">range</span>(<span style="color: #3677a9;">10</span>):
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">if</span> self.is_strike(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.next_two_rolls_for_strike(i)
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">1</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">elif</span> self.is_spare(i):
</span></span><span style="display: flex;"><span>                result += <span style="color: #3677a9;">10</span>
</span></span><span style="display: flex;"><span>                result += self.next_roll_for_spare(i)
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>            <span style="color: #6ab825; font-weight: bold;">else</span>:
</span></span><span style="display: flex;"><span>                result += self.rolls_in_frame(i)
</span></span><span style="display: flex;"><span>                i += <span style="color: #3677a9;">2</span>
</span></span></code></pre></div><p>Le code se “lit” quasiment comme les règles du bowling. Il a l’air correct, et il <em>est</em> correct.</p>
<p>Ensuite, même si notre refléxion initiale nous a guidé (notamment avec la classe Game et ses deux méthodes),
notez qu’on a pas eu besoin des classes <code>Frame</code> ou <code>Roll</code>, ni de la classe fille <code>TenthFrame</code>. En ce sens, on peut dire que TDD est également
une façon de <em>concevoir</em> le code, et pas juste une façon de faire évoluer le code de production et le code de test en parallèle.</p>
<p>Enfin, on avait un moyen de savoir quand le code était <em>fini</em>. Quand on pratique TDD, on sait qu’on peut s’arrêter dès que tous les tests
passent. Et, d’après l’ensemble des règles, on sait qu’on a écrit <em>uniquement</em> le code <em>nécessaire</em>.</p>
<h1 id="pour-aller-plus-loin">Pour aller plus loin <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#pour-aller-plus-loin">#</a></h1>
<p>Plusieurs remarques :</p>
<p>1/ La méthode <code>roll()</code> peut être appelée un nombre trop grand de fois, comme le prouve le test suivant :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">def</span> <span style="color: #447fcf;">test_two_many_rolls</span>():
</span></span><span style="display: flex;"><span>   game = GameTest()
</span></span><span style="display: flex;"><span>   game.roll_many(<span style="color: #3677a9;">21</span>, <span style="color: #3677a9;">1</span>)
</span></span><span style="display: flex;"><span>   <span style="color: #6ab825; font-weight: bold;">assert</span> game.score() == <span style="color: #3677a9;">20</span>
</span></span></code></pre></div><p>Savoir si c’est un bug ou non dépend des spécifications.</p>
<p>2/ Il y a probablement une classe ou une méthode cachée dans la classe <code>Game</code>. En effet, on a plusieurs méthodes qui prennent toutes un index en premier paramètre, et le paramètre en question nécessite un commentaire pour être compris.</p>
<p>Résoudre ces deux problèmes sera laissé en exercice au lecteur :P</p>
<h1 id="conclusion">Conclusion <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusion">#</a></h1>
<p>Voilà pour cette présentation sur le TDD. Je vous recommande d’essayer cette méthode par vous-mêmes. En ce qui me concerne elle a changé ma façon d’écrire du code en profondeur, et après plus de 5 ans de pratique, j’ai du mal à envisager de coder autrement.</p>
<p>À +</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>C’est payant, c’est en anglais, les exemples sont en Java, mais c’est vraiment très bien. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:1">↩︎</a></p>
</li>
<li id="fn:2">
<p>Par exemple, quand on lance python avec l’option <code>-O</code> <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:2">↩︎</a></p>
</li>
<li id="fn:3">
<p>Voir <a href="https://dmerej.info/blog/fr/post/bibliotheques-tierces-python/">cet article</a> pour comprendre pourquoi on procède ansi. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:3">↩︎</a></p>
</li>
<li id="fn:4">
<p>Il existe de nombreux outils pour palier aux limitations des tests, mais on en parlera une prochaine fois. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:4">↩︎</a></p>
</li>
<li id="fn:5">
<p>Les trois premières règles sont de Uncle Bob, la dernière est de moi. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:5">↩︎</a> <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref1:5">↩︎</a></p>
</li>
<li id="fn:6">
<p>Vous avez tout à fait le droit d’écrire du code en français. Mais au moindre doute sur la possibilité qu’un non-francophone doive lire votre code un jour, vous <em>devez</em> passer à l’anglais. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:6">↩︎</a></p>
</li>
<li id="fn:7">
<p>Si cette façon de commenter du code vous intrigue, vous pouvez lire <a href="https://hackaday.com/2019/03/05/good-code-documents-itself-and-other-hilarious-jokes-you-shouldnt-tell-yourself/">cet excellent article</a> (en anglais) pour plus de détails. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:7">↩︎</a></p>
</li>
</ol>
</div>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>Porter un gros project vers Python3</title>
        <link href="https://dmerej.info/blog/fr/post/porter-un-gros-projet-vers-python3/" />
        <id>https://dmerej.info/blog/fr/post/porter-un-gros-projet-vers-python3/</id>
        <updated>2019-05-15T12:38:15Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <h1 id="port-dun-gros-projet-vers-python3---retour-dexpérience">Port d’un gros projet vers Python3 - Retour d’expérience <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#port-dun-gros-projet-vers-python3---retour-dexp%c3%a9rience">#</a></h1>
<h2 id="introduction--le-projet-en-question">Introduction : le projet en question <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#introduction--le-projet-en-question">#</a></h2>
<p>Il s’agit d’une collection d’outils en ligne de commande que j’ai
développé dans mon ancienne boîte, les points importants étant</p>
<ul>
<li>la taille du projet: un peu moins de 30,000 lignes de code, et</li>
<li>l’ancienneté du code: près de 6 ans, qui initialement a tourné avec Python 2.6 (eh oui)</li>
</ul>
<h2 id="le-challenge">Le challenge <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#le-challenge">#</a></h2>
<p>On veut garder la rétro-compat vers Python2.7, histoire que la transition
se fasse en douceur.</p>
<p>On veut aussi pouvoir continuer les développements en Python2 sans attendre
la fin du port.</p>
<h2 id="à-faire-avant-de-commencer-à-porter">À faire avant de commencer à porter <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#%c3%a0-faire-avant-de-commencer-%c3%a0-porter">#</a></h2>
<h3 id="visez-la-bonne-version-de-python">Visez la bonne version de Python <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#visez-la-bonne-version-de-python">#</a></h3>
<p>Déjà, si vous supportez à la fois Python2 et Python3, vous pouvez
(et devez) <strong>ignorer les versions de Python comprises entre 3.0 et 3.2
inclus</strong>.</p>
<p>Les utilisateurs de distros “archaïques” (genre Ubuntu 12.04)
avec un vieux Python3 pourront tout à fait continuer à utiliser la version Python2.</p>
<h3 id="ayez-une-bonne-couverture-de-tests">Ayez une bonne couverture de tests <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#ayez-une-bonne-couverture-de-tests">#</a></h3>
<p><strong>Ne vous lancez pas dans le port sans une bonne couverture de tests</strong>.</p>
<p>Les changements entre Python2 et Python3 sont parfois très subtils,
donc sans une bonne couverture de tests vous risquez d’introduire
pas mal de régressions.</p>
<p>Dans mon cas, j’avais une couverture de 80%, et la plupart des problèmes ont été
trouvés par les (nombreux) tests automatiques (un peu plus de 900)</p>
<h2 id="le-port-proprement-dit">Le port proprement dit <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#le-port-proprement-dit">#</a></h2>
<h3 id="marche-à-suivre">Marche à suivre <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#marche-%c3%a0-suivre">#</a></h3>
<p>Voici les étapes que j’ai suivies. Il faut savoir qu’à la base je comptais
passer directement en Python3, sans être compatible Python2, mais en cours
de route je me suis aperçu que ça ne coûtait pas très cher de rendre
le code “polyglotte” (c’est comme ça qu’on dit) une fois le gros du travail
pour Python3 effectué.</p>
<ol>
<li>Lancez <code>2to3</code> et faites un commit avec le patch généré</li>
<li>Lancez les tests en Python3 jusqu’à ce qu’ils passent tous</li>
<li>Relancez tous les tests en Python2, en utilisant <code>six</code> pour rendre
le code polyglotte.</li>
<li>Assurez vous que tous les tests continuent à passer en Python3, commitez
et poussez.</li>
</ol>
<p>Note 1 : je ne connaissais pas <a href="http://python-future.org/">python-future</a> à
l’époque. Il contient un outil appelé <code>futurize</code> qui transforme directement
du code Python2 en code polyglotte. Si vous avez des retours à faire sur cet
outil, partagez !</p>
<p>Note 2 : Vous n’êtes bien sûr pas obligés d’utiliser <code>six</code> si vous n’avez pas
envie. Vous pouvez vous en sortir avec des <code>if sys.version_info()[1] &lt; 3</code>, et autres
<code>from __future__ import</code> (voir plus bas). Mais certaines fonctionnalités de <code>six</code>
sont compliquées à ré-implémenter à la main.</p>
<p>Note 3 : il existe aussi <a href="https://github.com/timothycrosley/pies">pies</a>
comme alternative à <code>six</code>. Voir
<a href="https://github.com/timothycrosley/pies#how-does-pies-differ-from-six">ici</a>
pour une liste des différences avec <code>six</code>. Personnellement, je trouve
<code>pies</code> un peu trop “magique” et je préfère rester explicite. De plus,
<code>six</code> semble être devenu le “standard” pour le code Python polyglotte.</p>
<p>Voyons maintenant quelques exemples de modifications à effectuer.</p>
<h3 id="print">print <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#print">#</a></h3>
<p>C’est le changement qui a fait le plus de bruit. Il est très facile
de faire du code polyglotte quand on utilise <code>print</code>. Il suffit de faire le bon import au début du fichier.</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">from</span> <span style="color: #447fcf; text-decoration: underline;">__future__</span> <span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #24909d;">print</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #24909d;">print</span>(<span style="color: #ed9d13;">"bar:"</span>, bar)
</span></span></code></pre></div><p>Notes:</p>
<ul>
<li>
<p>L’import de <code>__future__</code> doit être fait en premier</p>
</li>
<li>
<p>Il faut le faire sur <em>tous</em> les fichiers qui utilisent <code>print</code></p>
</li>
<li>
<p>Il est nécessaire pour avoir le même comportement en Python2 et
Pyton3. En effet, sans la ligne d’import, <code>print("bar:", "bar")</code> en
Python2 est lu comme “afficher le tuple <code>("foo", bar)</code>”, ce qui n’est
probablement pas le comportement attendu.</p>
</li>
</ul>
<h3 id="bytes-str-unicode">bytes, str, unicode <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#bytes-str-unicode">#</a></h3>
<p>Ça c’est le gros morceau.</p>
<p>Il n’y a pas de solution miracle, partout où vous avez des chaînes de
caractères, il va falloir savoir si vous voulez une chaîne de caractères
“encodée” (<code>str</code> en Python2, <code>bytes</code> en Python3) ou “décodée” (<code>unicode</code> en
Python2, <code>str</code> en Python3)</p>
<p>Deux articles de Sam qui abordent très bien la question:</p>
<ul>
<li><a href="http://sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/">L’encoding en Python, une bonne fois pour toute</a></li>
<li><a href="http://sametmax.com/en-python-3-le-type-bytes-est-un-array-dentiers/">En Python3 le type bytes est un tableau d’entiers</a></li>
</ul>
<p>Allez les (re)-lire si c’est pas déjà fait.</p>
<p>En résumé :</p>
<ul>
<li>Utilisez UTF-8</li>
<li>Décodez toutes les entrées</li>
<li>Encodez toutes les sorties</li>
</ul>
<p>J’ai vu conseiller de faire <code>from __future__ import unicode_literals</code>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># avec from __future__ import unicode_literals</span>
</span></span><span style="display: flex;"><span>a = <span style="color: #ed9d13;">"foo"</span>
</span></span><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #24909d;">type</span>(a)
</span></span><span style="display: flex;"><span>&lt;<span style="color: #24909d;">type</span> <span style="color: #ed9d13;">'unicode'</span>&gt;
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># sans</span>
</span></span><span style="display: flex;"><span>a = <span style="color: #ed9d13;">"foo"</span>
</span></span><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #24909d;">type</span>(a)
</span></span><span style="display: flex;"><span>&lt;<span style="color: #24909d;">type</span> <span style="color: #ed9d13;">'str'</span>&gt;
</span></span></code></pre></div><p>Personnellement je m’en suis sorti sans. À vous de voir.</p>
<h3 id="les-imports-relatifs-et-absolus">Les imports relatifs et absolus <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#les-imports-relatifs-et-absolus">#</a></h3>
<p>Personnellement, j’ai tendance à n’utiliser <em>que</em> des imports absolus.</p>
<p>Faisons l’hypothèse que vous avez installé un module externe <code>bar</code>,
dans votre système (ou dans votre virtualenv) et que vous avez déjà un fichier
<code>bar.py</code> dans vos sources.</p>
<p>Les imports absolus ne changent pas l’ordre de résolution quand
vous n’êtes pas dans un paquet. Si vous avez un fichier <code>foo.py</code> et un
fichier <code>bar.py</code> côte à côte, Python trouvera <code>bar</code> dans le répertoire courant.</p>
<p>En revanche, si vous avec une arborescence comme suit :</p>
<pre tabindex="0"><code>src
  foo
      __init__.py
      bar.py
</code></pre><p>Avec</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># in foo/__init__.py</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">bar</span>
</span></span></code></pre></div><p>En Python2, c’est <code>foo/bar.py</code> qui sera utilisé, et non <code>lib/site-packages/bar.py</code>. En Python3 ce sera l’inverse,
le fichier <code>bar.py</code>, <em>relatif</em> à <code>foo/__init__</code> aura la priorité.</p>
<p>Pour vous éviter ce genre de problèmes, utilisez donc :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">from</span> <span style="color: #447fcf; text-decoration: underline;">__future__</span> <span style="color: #6ab825; font-weight: bold;">import</span> absolute_import
</span></span></code></pre></div><p>Ou bien rendez votre code plus explicite en utilisant un point :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">from</span> <span style="color: #447fcf; text-decoration: underline;">.</span> <span style="color: #6ab825; font-weight: bold;">import</span> bar
</span></span></code></pre></div><p>Vous pouvez aussi:</p>
<ul>
<li>Changer le nom de votre module pour éviter les conflits.</li>
<li>Utiliser systématiquement <code>import foo.bar</code> (C’est ma solution
préférée)</li>
</ul>
<h3 id="la-division">La division <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#la-division">#</a></h3>
<p>Même principe que pour <code>print</code>. Vous pouvez faire</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">from</span> <span style="color: #447fcf; text-decoration: underline;">__future__</span> <span style="color: #6ab825; font-weight: bold;">import</span> division
</span></span></code></pre></div><p>et <code>/</code> fera toujours une division flottante, même utilisé avec des entiers.</p>
<p>Pour retrouver la division entière, utilisez <code>//</code>.</p>
<p>Example:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #3677a9;">5</span>/<span style="color: #3677a9;">2</span>
</span></span><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #3677a9;">2.5</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #3677a9;">3</span>
</span></span></code></pre></div><p>Note: celui-ci est assez vicieux à détecter …</p>
<h3 id="les-changements-de-noms">Les changements de noms <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#les-changements-de-noms">#</a></h3>
<p>De manière générale, le module <code>six.moves</code> contient tout ce qu’il faut
pour résoudre les problèmes de changement de noms.</p>
<p>Allez voir la table des cas traités par <code>six</code>
<a href="https://pythonhosted.org/six/#module-six.moves">ici</a></p>
<p><code>six</code> est notamment indispensable pour supporter les métaclasses, dont
la syntaxe a complètement changé entre Python2 et Python3. (Ne vous amusez
pas à recoder ça vous-mêmes, c’est velu)</p>
<p>Avec <code>six</code>, vous pouvez écrire</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #ffa500;">@six.add_metaclass</span>(Meta)
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">Foo</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">pass</span>
</span></span></code></pre></div><h3 id="range-et-xrange">range et xrange <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#range-et-xrange">#</a></h3>
<p>En Python2, <code>range()</code> est “gourmand” et retourne la liste entière dès qu’on
l’appelle, alors qu’en Python3, <code>range()</code> est “feignant” et retourne un
itérateur produisant les éléments sur demande. En Python2, si vous
voulez un itérateur, il faut utiliser <code>xrange()</code>.</p>
<p>Partant de là, vous avez deux solutions:</p>
<ul>
<li>
<p>Utiliser <code>range</code> tout le temps, même quand vous utilisiez
<code>xrange</code> en Python2. Bien sûr il y aura un coût en performance, mais
à vous de voir s’il est négligeable ou non.</p>
</li>
<li>
<p>Ou bien utiliser <code>six.moves.range()</code> qui vous retourne un itérateur
dans tous les cas.</p>
</li>
</ul>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">six</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>my_iterator = six.moves.range(<span style="color: #3677a9;">0</span>, <span style="color: #3677a9;">3</span>)
</span></span></code></pre></div><h3 id="les-vues-des-dictionnaires">Les “vues” des dictionnaires <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#les-vues-des-dictionnaires">#</a></h3>
<p>On va prendre un exemple:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>my_dict = { <span style="color: #ed9d13;">"a"</span> : <span style="color: #3677a9;">1</span> }
</span></span><span style="display: flex;"><span>keys = my_dict.keys()
</span></span></code></pre></div><p>Quand vous lancez <code>2to3</code>, ce code est remplacé par:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>my_dict = { <span style="color: #ed9d13;">"a"</span> : <span style="color: #3677a9;">1</span> }
</span></span><span style="display: flex;"><span>keys = <span style="color: #24909d;">list</span>(my_dict.keys())
</span></span></code></pre></div><p>C’est très laid :/</p>
<p>En fait en Python3, <code>keys()</code> retourne une “vue”, ce qui est différent de
la liste que vous avez en Python2, mais qui est <em>aussi</em> différent de l’itérateur
que vous obtenez avec <code>iterkeys()</code> en Python2. En vrai ce sont des
<a href="https://docs.python.org/2/library/stdtypes.html#dictionary-view-objects">view objects</a>.</p>
<p>La plupart du temps, cependant, vous voulez juste itérer sur les clés
et donc je recommande d’utiliser <code>2to3</code> avec <code>--nofix=dict</code>.</p>
<p>Bien sûr, <code>keys()</code> est plus lent en Python2, mais comme pour
<code>range</code> vous pouvez ignorer ce détail la plupart du temps.</p>
<p>Faites attention cependant, le code plantera si vous faites :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>my_dict = { <span style="color: #ed9d13;">"a"</span> : <span style="color: #3677a9;">1</span> }
</span></span><span style="display: flex;"><span>keys = my_dict.keys()
</span></span><span style="display: flex;"><span>keys.sort()
</span></span></code></pre></div><p>La raison est que les vues n’ont pas de méthode <code>sort</code>. À la place, utilisez :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>my_dict = { <span style="color: #ed9d13;">"a"</span> : <span style="color: #3677a9;">1</span> }
</span></span><span style="display: flex;"><span>keys = <span style="color: #24909d;">sorted</span>(my_dict.keys())
</span></span></code></pre></div><p>Enfin, il existe un cas pathologique : celui où le dictionnaire change
pendant que vous itérez sur les clés, par exemple:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">for</span> key <span style="color: #6ab825; font-weight: bold;">in</span> my_dict.keys():
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">if</span> something(key):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">del</span> my_dict[key]
</span></span></code></pre></div><p>Là, pas le choix, il faut faire :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">for</span> key <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">list</span>(my_dict.keys()):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">if</span> something(key):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">del</span> my_dict[key]
</span></span></code></pre></div><p>Ou</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">for</span> key <span style="color: #6ab825; font-weight: bold;">in</span> <span style="color: #24909d;">list</span>(six.iterkeys(my_dict)):
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">if</span> something(key):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">del</span> my_dict[key]
</span></span></code></pre></div><p>si vous préférez.</p>
<h3 id="les-exceptions">Les exceptions <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#les-exceptions">#</a></h3>
<p>En Python2, vous pouvez toujours écrire:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">raise</span> MyException, message
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">try</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># ....</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">except</span> MyException, e:
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># ...</span>
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># Do something with e.message</span>
</span></span></code></pre></div><p>C’est une très vielle syntaxe.</p>
<p>Le code peut être réécrit comme suit, et sera polyglotte :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">raise</span> MyException(message)
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">try</span>:
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># ....</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">except</span> MyException <span style="color: #6ab825; font-weight: bold;">as</span> e:
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># ....</span>
</span></span><span style="display: flex;"><span>    <span style="color: #999; font-style: italic;"># Do something with e.args</span>
</span></span></code></pre></div><p>Notez l’utilisation de <code>e.args</code> (une liste), et non
<code>e.message</code>. L’attribut <code>message</code> (une string) n’existe que dans
Python2. Vous pouvez utiliser <code>.args[0]</code> pour récupérer le message d’une
façon polyglotte.</p>
<h3 id="comparer-des-pommes-et-des-bananes">Comparer des pommes et des bananes <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#comparer-des-pommes-et-des-bananes">#</a></h3>
<p>En <code>Python2</code>, tout est ordonné:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #24909d;">print</span> <span style="color: #24909d;">sorted</span>([<span style="color: #ed9d13;">"1"</span>, <span style="color: #3677a9;">0</span>, <span style="color: #6ab825; font-weight: bold;">None</span>])
</span></span><span style="display: flex;"><span>[<span style="color: #6ab825; font-weight: bold;">None</span>, <span style="color: #3677a9;">0</span>, <span style="color: #ed9d13;">"1"</span>]
</span></span></code></pre></div><p>L’interpréteur n’a aucun souci avec le fait que vous tentiez d’ordonner une
string et un nombre.</p>
<p>En Python3, ça crashe:</p>
<pre tabindex="0"><code>TypeError: '&lt;' not supported between instances of 'int' and 'str'
</code></pre><p>Pensez y si vous avez des tris sur des classes à vous. La technique recommandée
c’est d’utiliser <code>@functools.total_ordering</code> et de définir <code>__lt__</code>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #ffa500;">@functools.total_ordering</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">class</span> <span style="color: #447fcf; text-decoration: underline;">MaClassPerso</span>():
</span></span><span style="display: flex;"><span>    ...
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>    <span style="color: #6ab825; font-weight: bold;">def</span> __lt__(self, other):
</span></span><span style="display: flex;"><span>        <span style="color: #6ab825; font-weight: bold;">return</span> self.quelque_chose &lt; other.quelque_chose
</span></span></code></pre></div><h3 id="le-ficher-setuppy">Le ficher setup.py <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#le-ficher-setuppy">#</a></h3>
<p>Assurez vous de spécifier les versions de Python supportées dans votre
<code>setup.py</code></p>
<p>Par exemple, si vous supportez à la fois Python2 et Python3, utilisez :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">from</span> <span style="color: #447fcf; text-decoration: underline;">setuptools</span> <span style="color: #6ab825; font-weight: bold;">import</span> setup, find_packages
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>setup(name=<span style="color: #ed9d13;">"foo"</span>,
</span></span><span style="display: flex;"><span>      <span style="color: #999; font-style: italic;"># ...</span>
</span></span><span style="display: flex;"><span>      classifiers = [
</span></span><span style="display: flex;"><span>        <span style="color: #999; font-style: italic;"># ...</span>
</span></span><span style="display: flex;"><span>        <span style="color: #ed9d13;">"Programming Language :: Python :: 2"</span>,
</span></span><span style="display: flex;"><span>        <span style="color: #ed9d13;">"Programming Language :: Python :: 3"</span>,
</span></span><span style="display: flex;"><span>      ],
</span></span><span style="display: flex;"><span>      <span style="color: #999; font-style: italic;"># ...</span>
</span></span><span style="display: flex;"><span>)
</span></span></code></pre></div><p>Et ajoutez un <code>setup.cfg</code> comme suit :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>[bdist_wheel]
</span></span><span style="display: flex;"><span>universal = <span style="color: #3677a9;">1</span>
</span></span></code></pre></div><p>pour générer une <code>wheel</code> compatible Python2 et Python3.</p>
<h2 id="deux-trois-mots-sur-lintégration-continue">Deux trois mots sur l’intégration continue <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#deux-trois-mots-sur-lint%c3%a9gration-continue">#</a></h2>
<p>Comme mentionné plus haut, le développement du projet a dû continuer
sans attendre que le support de Python3 soit mergé.</p>
<p>Le port a donc dû se faire dans une autre branche (que j’ai appelé <code>six</code>)</p>
<p>Du coup, comment faire pour que la branche ‘six’ reste à jour ?</p>
<p>La solution passe par l’intégration continue. Dans mon cas j’utilise
<a href="https://jenkins-ci.org/">jenkins</a></p>
<p>À chaque commit sur la branche de développement, voici ce qu’il se passe:</p>
<ul>
<li>La branche ‘six’ est rebasée</li>
<li>Les tests sont lancés avec Python2 puis Python3</li>
<li>La branche est poussée (avec <code>--force</code>).</li>
</ul>
<p>Si l’une des étapes ne fonctionne pas (par exemple, le rebase ne
passe pas à cause de conflits, ou bien l’une des suites de test échoue),
l’équipe est prévenue par mail.</p>
<p>Ainsi la branche <code>six</code> continue d’être “vivante” et il est trivial et
sans risque de la fusionner dans la branche de développement au moment
opportun.</p>
<h2 id="conclusion">Conclusion <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusion">#</a></h2>
<p>J’aimerais remercier Eric S. Raymond qui m’a donné l’idée de ce billet suite
à <a href="http://esr.ibiblio.org/?p=7039">un article sur son blog</a> et m’a autorisé
à contribuer à son
<a href="http://www.catb.org/esr/faqs/practical-python-porting/">HOWTO</a>, suite
à ma
<a href="https://github.com/dmerejkowsky/response-to-practical-python-porting-by-esr">réponse</a></p>
<p>N’hésitez pas en commentaire à partager votre propre expérience
(surtout si vous avez procédé différemment) ou vos questions, j’essaierai
d’y répondre.</p>
<p>Il vous reste jusqu’à la fin de l’année avant l’arrêt du support de Python2 en 2020,
et ce coup-là il n’y aura probablement pas de report. Au boulot !</p>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>Utiliser des bibliothèques tierces avec Python</title>
        <link href="https://dmerej.info/blog/fr/post/bibliotheques-tierces-python/" />
        <id>https://dmerej.info/blog/fr/post/bibliotheques-tierces-python/</id>
        <updated>2019-05-05T13:10:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Note : cet article reprend en grande partie le cours donné à <a href="https://e2li.org">l’École du Logiciel Libre</a> le 4 mai 2019.</p>
<p>Quelques rappels pour commencer.</p>
<h1 id="importer-un-module">Importer un module <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#importer-un-module">#</a></h1>
<p>Soit le code suivant :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">foo</span>
</span></span><span style="display: flex;"><span>foo.bar()
</span></span></code></pre></div><p>Ce code fonctionne s’il y a un ficher <code>foo.py</code> quelque part qui contient la fonction <code>bar</code> <sup id="fnref:1"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:1">1</a></sup></p>
<p>Ce fichier peut être présent soit dans le répertoire courant, soit dans la bibliothèque standard Python.</p>
<h1 id="la-variable-path">La variable PATH <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#la-variable-path">#</a></h1>
<p>Vous connaissez peut-être le rôle de la variable d’environnement <code>PATH</code>. Celle-ci contient une liste de chemins,
et est utilisée par votre shell pour trouver le chemin complet des commandes que vous lancez.</p>
<p>Par exemple:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span><span style="color: #40ffff;">PATH</span>=<span style="color: #ed9d13;">"/bin:/usr/bin:/usr/sbin"</span>
</span></span><span style="display: flex;"><span>$ ifconfig
</span></span><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># lance le binaire /usr/sbin/ifconfig</span>
</span></span><span style="display: flex;"><span>$ ls
</span></span><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># lance le binaire /bin/ls</span>
</span></span></code></pre></div><p>Le chemin est “résolu” par le shell en parcourant la liste de tout les segments de <code>PATH</code>, et en regardant si le chemin complet
existe. La résolution s’arrête dès le premier chemin trouvé.</p>
<p>Par exemple, si vous avez <code>PATH="/home/user/bin:/usr/bin"</code> et un fichier <code>ls</code> dans <code>/home/user/bin/ls</code>, c’est ce fichier-là
(et non <code>/bin/ls</code>) qui sera utilisé quand vous taperez <code>ls</code>.</p>
<h1 id="syspath">sys.path <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#syspath">#</a></h1>
<p>En Python, il existe une variable <code>path</code> prédéfinie dans le module <code>sys</code> qui fonctionne de manière similaire.</p>
<p>Si j’essaye de l’afficher sur mon Arch Linux, voici ce que j’obtiens :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>&gt;&gt;&gt; <span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">sys</span>
</span></span><span style="display: flex;"><span>&gt;&gt;&gt; sys.path
</span></span><span style="display: flex;"><span>[
</span></span><span style="display: flex;"><span> <span style="color: #ed9d13;">""</span>,
</span></span><span style="display: flex;"><span> <span style="color: #ed9d13;">"/usr/lib/python3.7"</span>,
</span></span><span style="display: flex;"><span> <span style="color: #ed9d13;">"/usr/lib/python3.7/lib-dynload"</span>,
</span></span><span style="display: flex;"><span> <span style="color: #ed9d13;">"/home/dmerej/.local/lib/python3.7/"</span>,
</span></span><span style="display: flex;"><span> <span style="color: #ed9d13;">"/usr/lib/python3.7/site-packages"</span>,
</span></span><span style="display: flex;"><span>]
</span></span></code></pre></div><p>Notez que le résultat dépend de ma distribution, et de la présence ou non du répertoire <code>~/.local/lib/python3.7/</code> sur ma machine - cela prouve que <code>sys.path</code> est construit dynamiquement par l’interpréteur Python.</p>
<p>Notez également que <code>sys.path</code> commence par une chaîne vide. En pratique, cela signifie que le répertoire courant a la priorité sur tout le reste.</p>
<p>Ainsi, si vous avez un fichier <code>random.py</code> dans votre répertoire courant, et que vous lancez un script <code>foo.py</code> dans ce même répertoire, vous vous retrouvez à utiliser le code dans <code>random.py</code>, et non celui de la bibliothèque standard ! Pour information, la liste de tous les modules de la bibliothèque standard est présente dans <a href="https://docs.python.org/fr/3/library/index.html">la documentation</a>.</p>
<p>Un autre aspect notable de <code>sys.path</code> est qu’il ne contient que deux répertoires dans lesquels l’utilisateur courant peut potentiellement écrire : le chemin courant et le chemin dans <code>~/.local/lib</code>. Tous les autres (<code>/usr/lib/python3.7/</code>, etc.) sont des chemins “système” et ne peuvent être modifiés que par un compte administrateur (avec <code>root</code> ou <code>sudo</code>, donc).</p>
<p>La situation est semblable sur macOS et Windows <sup id="fnref:2"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:2">2</a></sup>.</p>
<h1 id="bibliothèques-tierces">Bibliothèques tierces <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#biblioth%c3%a8ques-tierces">#</a></h1>
<p>Prenons un exemple :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># dans foo.py</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">tabulate</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>scores = [
</span></span><span style="display: flex;"><span>  [<span style="color: #ed9d13;">"John"</span>, <span style="color: #3677a9;">345</span>],
</span></span><span style="display: flex;"><span>  [<span style="color: #ed9d13;">"Mary-Jane"</span>, <span style="color: #3677a9;">2</span>],
</span></span><span style="display: flex;"><span>  [<span style="color: #ed9d13;">"Bob"</span>, <span style="color: #3677a9;">543</span>],
</span></span><span style="display: flex;"><span>]
</span></span><span style="display: flex;"><span>table = tabulate.tabulate(scores)
</span></span><span style="display: flex;"><span><span style="color: #24909d;">print</span>(table)
</span></span></code></pre></div><pre tabindex="0"><code>$ python3 foo.py
---------  ---
John       345
Mary-Jane    2
Bob        543
---------  ---
</code></pre><p>Ici, le module <code>tabulate</code> n’est ni dans la bibliothèque standard, ni écrit par l’auteur du script <code>foo.py</code>. On dit que c’est une bibliothèque tierce.</p>
<p>On peut trouver <a href="https://bitbucket.org/astanin/python-tabulate/src/master/">le code source de tabulate</a> facilement. La question qui se pose alors est: comment faire en sorte que <code>sys.path</code> contienne le module <code>tabulate</code>?</p>
<p>Eh bien, plusieurs solutions s’offrent à vous.</p>
<h1 id="le-gestionnaire-de-paquets">Le gestionnaire de paquets <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#le-gestionnaire-de-paquets">#</a></h1>
<p>Si vous utilisez une distribution Linux, peut-être pourrez-vous utiliser votre gestionnaire de paquets :</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ sudo apt install python3-tabulate
</span></span></code></pre></div><p>Comme vous lancez votre gestionnaire de paquets avec <code>sudo</code>, celui-ci sera capable d’écrire dans les chemins système de <code>sys.path</code>.</p>
<h1 id="à-la-main">À la main <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#%c3%a0-la-main">#</a></h1>
<p>Une autre méthode consiste à partir des sources - par exemple, si le paquet de votre distribution n’est pas assez récent, ou si vous avez besoin de modifier le code de la bibliothèque en question.</p>
<p>Voici une marche à suivre possible :</p>
<ol>
<li>Récupérer les sources de la version qui vous intéresse dans la <a href="https://bitbucket.org/astanin/python-tabulate/downloads/?tab=tags">section téléchargement de bitbucket</a>.</li>
<li>Extraire l’archive, par exemple dans <code>src/tabulate</code></li>
<li>Se rendre dans <code>src/tabulate</code> et lancer <code>python3 setup.py install --user</code></li>
</ol>
<h1 id="anatomie-du-fichier-setuppy">Anatomie du fichier setup.py <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#anatomie-du-fichier-setuppy">#</a></h1>
<p>La plupart des bibliothèques Python contiennent un <code>setup.py</code> à
la racine de leurs sources. Il sert à plein de choses, la commande <code>install</code>
n’étant qu’une parmi d’autres.</p>
<p>Le fichier <code>setup.py</code> contient en général simplement un <code>import</code> de <code>setuptools</code>, et un appel à la fonction <code>setup()</code>, avec de nombreux arguments :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># tabulate/setup.py</span>
</span></span><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">from</span> <span style="color: #447fcf; text-decoration: underline;">setuptools</span> <span style="color: #6ab825; font-weight: bold;">import</span> setup
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>setup(
</span></span><span style="display: flex;"><span>  name=<span style="color: #ed9d13;">'tabulate'</span>,
</span></span><span style="display: flex;"><span>  version=<span style="color: #ed9d13;">'0.8.1'</span>,
</span></span><span style="display: flex;"><span>  description=<span style="color: #ed9d13;">'Pretty-print tabular data'</span>,
</span></span><span style="display: flex;"><span>  py_modules=[<span style="color: #ed9d13;">"tabulate"</span>],
</span></span><span style="display: flex;"><span>  scripts=[<span style="color: #ed9d13;">"bin/tabulate"</span>],
</span></span><span style="display: flex;"><span>  ...
</span></span><span style="display: flex;"><span>)
</span></span></code></pre></div><h1 id="résultat-de-linvocation-de-setuppy">Résultat de l’invocation de setup.py <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#r%c3%a9sultat-de-linvocation-de-setuppy">#</a></h1>
<p>Par défaut, <code>setup.py</code> essaiera d’écrire dans un des chemins système de
<code>sys.path</code> <sup id="fnref:3"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:3">3</a></sup>, d’où l’utilisation de l’option <code>--user</code>.</p>
<p>Voici à quoi ressemble la sortie de la commande :</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ <span style="color: #24909d;">cd</span> src/tabulate
</span></span><span style="display: flex;"><span>$ python3 setup.py install --user
</span></span><span style="display: flex;"><span>running install
</span></span><span style="display: flex;"><span>...
</span></span><span style="display: flex;"><span>Copying tabulate-0.8.4-py3.7.egg to /home/dmerej/.local/lib/python3.7/site-packages
</span></span><span style="display: flex;"><span>...
</span></span><span style="display: flex;"><span>Installing tabulate script to /home/dmerej/.local/bin
</span></span></code></pre></div><p>Notez que module a été copié dans <code>~/.local/lib/python3.7/site-packages/</code> et le script dans <code>~/.local/bin</code>. Cela signifie que <em>tous</em> les scripts Python lancés par l’utilisateur courant auront accès au module <code>tabulate</code>.</p>
<p>Notez également qu’un script a été installé dans <code>~/.local/bin</code> - Une bibliothèque Python peut contenir aussi bien des modules que des scripts.</p>
<p>Un point important est que vous n’avez en général pas besoin de lancer le script directement. Vous pouvez utiliser <code>python3 -m tabulate</code>. Procéder de cette façon est intéressant puisque vous n’avez pas à vous soucier de rajouter le chemin d’installation des scripts dans la variable d’environnement PATH.</p>
<h1 id="dépendances">Dépendances <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#d%c3%a9pendances">#</a></h1>
<p>Prenons une autre bibliothèque : <code>cli-ui</code>.</p>
<p>Elle permet d’afficher du texte en couleur dans un terminal</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #6ab825; font-weight: bold;">import</span> <span style="color: #447fcf; text-decoration: underline;">cli_ui</span>
</span></span><span style="display: flex;"><span>
</span></span><span style="display: flex;"><span>cli_ui.info(<span style="color: #ed9d13;">"Ceci est en"</span>, cli_ui.red, <span style="color: #ed9d13;">"rouge"</span>)
</span></span></code></pre></div><p>Elle permet également d’afficher des tableaux en couleur :</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>headers=[<span style="color: #ed9d13;">"name"</span>, <span style="color: #ed9d13;">"score"</span>]
</span></span><span style="display: flex;"><span>data = [
</span></span><span style="display: flex;"><span>  [(bold, <span style="color: #ed9d13;">"John"</span>), (green, <span style="color: #3677a9;">10.0</span>)],
</span></span><span style="display: flex;"><span>  [(bold, <span style="color: #ed9d13;">"Jane"</span>), (green, <span style="color: #3677a9;">5.0</span>)],
</span></span><span style="display: flex;"><span>]
</span></span><span style="display: flex;"><span>cli_ui.info_table(data, headers=headers)
</span></span></code></pre></div><p>Pour ce faire, elle repose sur la bibliothèque <code>tabulate</code> vue précédemment. On dit que <code>cli-ui</code> <em>dépend</em> de <code>tabulate</code>.</p>
<h1 id="déclaration-des-dépendances">Déclaration des dépendances <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#d%c3%a9claration-des-d%c3%a9pendances">#</a></h1>
<p>La déclaration de la dépendance de <code>cli-ui</code> vers <code>tabulate</code> s’effectue également dans le fichier <code>setup.py</code>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>setup(
</span></span><span style="display: flex;"><span>  name=<span style="color: #ed9d13;">"cli-ui"</span>,
</span></span><span style="display: flex;"><span>  version=<span style="color: #ed9d13;">"0.9.1"</span>,
</span></span><span style="display: flex;"><span>  install_requires=[
</span></span><span style="display: flex;"><span>     <span style="color: #ed9d13;">"tabulate"</span>,
</span></span><span style="display: flex;"><span>     ...
</span></span><span style="display: flex;"><span>  ],
</span></span><span style="display: flex;"><span>  ...
</span></span><span style="display: flex;"><span>)
</span></span></code></pre></div><h1 id="pypiorg">pypi.org <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#pypiorg">#</a></h1>
<p>On comprend dès lors qu’il doit nécessairement exister un <em>annuaire</em> permettant de relier les noms de dépendances à leur code source.</p>
<p>Cet annuaire, c’est le site <a href="https://pypi.org/">pypi.org</a>. Vous y trouverez les pages correspondant à <a href="https://pypi.org/project/tabulate/">tabulate</a> et <a href="https://pypi.org/project/python-cli-ui/">cli-ui</a>.</p>
<h1 id="pip">pip <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#pip">#</a></h1>
<p><code>pip</code> est un outil qui vient par défaut avec Python3<sup id="fnref:4"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:4">4</a></sup>. Vous pouvez également l’installer grâce au script <a href="https://bootstrap.pypa.io/get-pip.py">get-pip.py</a>, en lançant <code>python3 get-pip.py --user</code>.</p>
<p>Il est conseillé de <em>toujours</em> lancer <code>pip</code> avec <code>python3 -m pip</code>. De cette façon, vous êtes certains d’utiliser le module <code>pip</code> correspondant à votre binaire <code>python3</code>, et vous ne dépendez pas de ce qu’il y a dans votre <code>PATH</code>.</p>
<p><code>pip</code> est capable d’interroger le site <code>pypi.org</code> pour retrouver les dépendances, et également de lancer les différents scripts <code>setup.py</code>.</p>
<p>Comme de nombreux outils, il s’utilise à l’aide de <em>commandes</em>. Voici comment installer <code>cli-ui</code> à l’aide de la commande ‘install’ de  <code>pip</code>:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ python3 -m pip install cli-ui --user
</span></span><span style="display: flex;"><span>Collecting cli-ui
</span></span><span style="display: flex;"><span>...
</span></span><span style="display: flex;"><span>Requirement already satisfied: unidecode in /usr/lib/python3.7/site-packages (from cli-ui) (1.0.23)
</span></span><span style="display: flex;"><span>Requirement already satisfied: colorama in /usr/lib/python3.7/site-packages (from cli-ui) (0.4.1)
</span></span><span style="display: flex;"><span>Requirement already satisfied: tabulate in /mnt/data/dmerej/src/python-tabulate (from cli-ui) (0.8.4)
</span></span><span style="display: flex;"><span>Installing collected packages: cli-ui
</span></span><span style="display: flex;"><span>Successfully installed cli-ui-0.9.1
</span></span></code></pre></div><p>On constate ici quelques limitations de <code>pip</code>:</p>
<ul>
<li>Il faut penser à utiliser <code>--user</code> (de la même façon que lorsqu’on lance <code>setup.py</code> à la main)</li>
<li>Si le paquet est déjà installé dans le système, pip ne saura pas le mettre à jour - il faudra passer par le gestionnaire de paquet de
la distribution</li>
</ul>
<p>En revanche, <code>pip</code> contient de nombreuses fonctionnalités intéressantes:</p>
<ul>
<li>Il est capable de désinstaller des bibliothèques (à condition toutefois qu’elles ne soient pas dans un répertoire système)</li>
<li>Il est aussi capable d’afficher la liste complète des bibliothèques Python accessibles par l’utilisateur courant avec <code>freeze</code>.</li>
</ul>
<p>Voici un extrait de la commande <code>python3 -m pip freeze</code> au moment de la rédaction de cet article sur ma machine:</p>
<pre tabindex="0"><code>$ python3 -m pip freeze
apipkg==1.5
cli-ui==0.9.1
gaupol==1.5
tabulate==0.8.4
</code></pre><p>On y retrouve les bibliothèques <code>cli-ui</code> et <code>tabulate</code>, bien sûr, mais aussi la bibliothèque <code>gaupol</code>, qui correspond au <a href="https://otsaloma.io/gaupol/">programme d’édition de sous-titres</a> que j’ai installé à l’aide du gestionnaire de paquets de ma distribution. Précisons que les modules de la bibliothèque standard et ceux utilisés directement par pip sont omis de la liste.</p>
<p>On constate également que chaque bibliothèque possède un <em>numéro de version</em>.</p>
<h1 id="numéros-de-version">Numéros de version <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#num%c3%a9ros-de-version">#</a></h1>
<p>Les numéros de version remplissent plusieurs rôles, mais l’un des principaux est de spécifier des changements incompatibles.</p>
<p>Par exemple, pour <code>cli-ui</code>, la façon d’appeler la fonction <code>ask_choice</code> a changé entre les versions 0.7 et 0.8, comme le montre le <a href="https://dmerejkowsky.github.io/python-cli-ui/changelog.html">changelog</a>:</p>
<blockquote>
<p>the list of choices used by ask_choice is now a named keyword argument:</p>
</blockquote>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># Old (&lt;= 0.7)</span>
</span></span><span style="display: flex;"><span>ask_choice(<span style="color: #ed9d13;">"select a fruit"</span>, [<span style="color: #ed9d13;">"apple"</span>, <span style="color: #ed9d13;">"banana"</span>])
</span></span><span style="display: flex;"><span><span style="color: #999; font-style: italic;"># New (&gt;= 0.8)</span>
</span></span><span style="display: flex;"><span>ask_choice(<span style="color: #ed9d13;">"select a fruit"</span>, choices=[<span style="color: #ed9d13;">"apple"</span>, <span style="color: #ed9d13;">"banana"</span>])
</span></span></code></pre></div><p>Ceci s’appelle un <em>changement d’API</em>.</p>
<h1 id="réagir-aux-changements-dapi">Réagir aux changements d’API <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#r%c3%a9agir-aux-changements-dapi">#</a></h1>
<p>Plusieurs possibilités:</p>
<ul>
<li>On peut bien sûr adapter le code pour utiliser la nouvelle API, mais cela n’est pas toujours possible ni souhaitable.</li>
<li>Une autre solution est de spécifier des <em>contraintes</em> sur le numéro de version dans la déclaration des dépendances. Par exemple :</li>
</ul>
<div class="highlight"><pre tabindex="0"><code class="language-python"><span style="display: flex;"><span>setup(
</span></span><span style="display: flex;"><span>  install_requires=[
</span></span><span style="display: flex;"><span>    <span style="color: #ed9d13;">"cli-ui &lt; 0.8"</span>,
</span></span><span style="display: flex;"><span>    ...
</span></span><span style="display: flex;"><span>  ]
</span></span><span style="display: flex;"><span>)
</span></span></code></pre></div><h1 id="aparté--pourquoi-éviter-sudo-pip">Aparté : pourquoi éviter sudo pip <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#apart%c3%a9--pourquoi-%c3%a9viter-sudo-pip">#</a></h1>
<p>Souvenez-vous que les fichiers systèmes sont contrôlés par votre gestionnaire de paquets.</p>
<p>Les mainteneurs de votre distribution font en sorte qu’ils fonctionnent bien les uns
avec les autres. Par exemple, le paquet <code>python3-cli-ui</code> ne sera mis à jour que lorsque tous les paquets qui en dépendent seront prêts à utiliser la nouvelle API.</p>
<p>En revanche, si vous lancez <code>sudo pip</code> (où <code>pip</code> avec un compte root), vous allez écrire dans ces mêmes répertoire et vous risquez de “casser” certains programmes de votre système.</p>
<p>Mais il y a un autre problème encore pire.</p>
<h1 id="conflit-de-dépendances">Conflit de dépendances <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conflit-de-d%c3%a9pendances">#</a></h1>
<p>Supposons deux projets A et B dans votre répertoire personnel. Ils dépendent tous les deux de <code>cli-ui</code>, mais l’un des deux utilise <code>cli-ui 0.7</code> et l’autre <code>cli-ui 0.9</code>.  Que faire ?</p>
<h1 id="environnements-virtuels">Environnements virtuels <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#environnements-virtuels">#</a></h1>
<p>La solution est d’utiliser un environnement virtuel (<em>virtualenv</em> en abrégé). C’est un répertoire <em>isolé</em> du reste du système.</p>
<p>Pour créer un virtualenv il faut utiliser la commande:</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ python -m venv /chemin/vers/virtualenv
</span></span></code></pre></div><p>où <code>/chemin/vers/virtualenv</code> est le dossier cible. Les dossiers parents seront créés si nécessaire par le module <code>venv</code>.</p>
<p>En pratique, on préfère utiliser un chemin qui n’existe pas encore, typiquement :</p>
<div class="highlight"><pre tabindex="0"><code class="language-bash"><span style="display: flex;"><span>$ <span style="color: #24909d;">cd</span> /chemin/vers/project
</span></span><span style="display: flex;"><span>$ python -m .venv
</span></span></code></pre></div><p>Ici on a utilisé le répertoire relatif <code>.venv</code>.</p>
<h2 id="aparté--python3--m-venv-sur-debian">Aparté : python3 -m venv sur Debian <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#apart%c3%a9--python3--m-venv-sur-debian">#</a></h2>
<p>La commande <code>python3 -m venv</code> fonctionne en général partout, dès l’installation de Python3 (<em>out of the box</em>, en Anglais), <em>sauf</em> sur Debian et ses dérivées <sup id="fnref:5"><a class="footnote-ref" href="https://dmerej.info/blog/fr/index.xml#fn:5">5</a></sup>.</p>
<p>Si vous utilisez Debian, la commande pourrait ne pas fonctionner. En fonction des messages d’erreur que vous obtenez, il est possible de résoudre le problème en :</p>
<ul>
<li>installant le paquet <code>python3-venv</code>,</li>
<li>ou en utilisant d’abord <code>pip</code> pour installer <code>virtualenv</code>, avec <code>python3 -m pip install virtualenv --user</code> puis en lançant <code>python3 -m virtualenv foo-venv</code>.</li>
</ul>
<h2 id="comportement-de-python-dans-le-virtualenv">Comportement de python dans le virtualenv <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#comportement-de-python-dans-le-virtualenv">#</a></h2>
<p>Ce répertoire contient de nombreux fichiers et dossiers, et notamment un binaire dans <code>foo-venv/bin/python3</code>.</p>
<p>Voyons comment il se comporte en le comparant au binaire <code>/usr/bin/python3</code> habituel :</p>
<pre tabindex="0"><code>$ /usr/bin/python3 -c 'import sys; print(sys.path)'
['',
  ...
 '/usr/lib/python3.7',
 '/usr/lib/python3.7.zip',
 '/usr/lib/python3.7/lib-dynload',
 '/home/dmerej/.local/lib/python3.7/site-packages',
 '/usr/lib/python3.7/site-packages'
]

$ /home/dmerej/foo-venv/bin/python -c 'import sys; print(sys.path)'
['',
 '/usr/lib/python3.7',
 '/usr/lib/python3.7.zip',
 '/usr/lib/python3.7/lib-dynload',
 '/home/dmerej/foo-venv/lib/python3.7/site-packages,
]
</code></pre><p>À noter:</p>
<ul>
<li>Le répertoire “global” dans <code>~/.local/lib</code> a disparu</li>
<li>Seuls quelques répertoires systèmes sont présents (ils correspondent plus ou moins à l’emplacement des modules de la bibliothèque standard)</li>
<li>Un répertoire <em>au sein</em> du virtualenv a été rajouté</li>
</ul>
<p>Ainsi, l’isolation du virtualenv est reflété dans la différence de la valeur de <code>sys.path</code>.</p>
<p>Il faut aussi préciser que le virtualenv n’est pas complètement isolé du reste du système. En particulier, il dépend encore du binaire Python utilisé pour le créer.</p>
<p>Par exemple, si vous utilisez <code>/usr/local/bin/python3.7 -m venv foo-37</code>, le virtualenv dans <code>foo-37</code> utilisera Python 3.7 et fonctionnera tant que le binaire <code>/usr/local/bin/python3.7</code> existe.</p>
<p>Cela signifie également qu’il est possible qu’en mettant à jour le paquet <code>python3</code> sur votre distribution, vous rendiez inutilisables les virtualenvs créés avec l’ancienne version du paquet.</p>
<h2 id="comportement-de-pip-dans-le-virtualenv">Comportement de pip dans le virtualenv <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#comportement-de-pip-dans-le-virtualenv">#</a></h2>
<p>D’après ce qui précède, le virtualenv ne devrait contenir aucun module en dehors de la bibliothèque standard et de <code>pip</code> lui-même.</p>
<p>On peut s’en assurer en lançant <code>python3 -m pip freeze</code> depuis le virtualenv et en vérifiant que rien ne s’affiche.</p>
<pre tabindex="0"><code>$ python3 -m pip freeze
# de nombreuses bibliothèques en dehors du virtualenv
apipkg==1.5
cli-ui==0.9.1
gaupol==1.5
tabulate==0.8.4

$ /home/dmerej/foo-venv/bin/python3 -m pip freeze
# rien :)
</code></pre><p>On peut alors utiliser le module <code>pip</code> <em>du virtualenv</em> pour installer des bibliothèques dans celui-ci :</p>
<pre tabindex="0"><code>$ /home/dmerej/foo-venv/bin/python3 -m pip install cli-ui
Collecting cli-ui
  Using cached https://pythonhosted.org/..cli_ui-0.9.1-py3-none-any.whl
Collecting colorama (from cli-ui)
  Using cached https://pythonhosted.org/..colorama-0.4.1-py2.py3-none-any.whl
Collecting unidecode (from cli-ui)
  Using cached https://pythonhosted.org/..Unidecode-1.0.23-py2.py3-none-any.whl
Collecting tabulate (from cli-ui)
Installing collected packages: colorama, unidecode, tabulate, cli-ui
Successfully installed cli-ui-0.9.1 colorama-0.4.1 tabulate-0.8.3
  unidecode-1.0.23
</code></pre><p>Cette fois, aucune bibliothèque n’est marquée comme déjà installée, et on récupère donc <code>cli-ui</code> et toutes ses dépendances.</p>
<p>On a enfin notre solution pour résoudre notre conflit de dépendances :
on peut simplement créer un virtualenv par projet. Ceci nous permettra
d’avoir effectivement deux versions différentes de <code>cli-ui</code>, isolées les
unes des autres.</p>
<h1 id="activer-un-virtualenv">Activer un virtualenv <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#activer-un-virtualenv">#</a></h1>
<p>Devoir préciser le chemin du virtualenv en entier pour chaque commande peut devenir fastidieux ; heureusement, il est possible <em>d’activer</em> un virtualenv, en lançant une des commandes suivantes :</p>
<ul>
<li><code>source foo-venv/bin/activate</code> - si vous utilisez un shell POSIX</li>
<li><code>source foo-venv/bin/activate.fish</code> - si vous utilisez Fish</li>
<li><code>foo-venv\bin\activate.bat</code> - sous Windows</li>
</ul>
<p>Une fois le virtualenv activé, taper <code>python</code>, <code>python3</code> ou <code>pip</code> utilisera les binaires correspondants dans le virtualenv automatiquement,
et ce, tant que la session du shell sera ouverte.</p>
<p>Le script d’activation ne fait en réalité pas grand-chose à part modifier la variable <code>PATH</code> et rajouter le nom du virtualenv au début de l’invite de commandes :</p>
<pre tabindex="0"><code># Avant
user@host:~/src $ source foo-env/bin/activate
# Après
(foo-env) user@host:~/src $
</code></pre><p>Pour sortir du virtualenv, entrez la commande <code>deactivate</code>.</p>
<h1 id="conclusion">Conclusion <a class="anchor" href="https://dmerej.info/blog/fr/index.xml#conclusion">#</a></h1>
<p>Le système de gestions des dépendances de Python peut paraître compliqué et bizarre, surtout venant d’autres langages.</p>
<p>Mon conseil est de toujours suivre ces deux règles :</p>
<ul>
<li>Un virtualenv par projet et par version de Python</li>
<li>Toujours utiliser <code>pip</code> <em>depuis</em> un virtualenv</li>
</ul>
<p>Certes, cela peut paraître fastidieux, mais c’est une méthode qui vous évitera probablement de vous arracher les cheveux (croyez-en mon expérience).</p>
<p>Dans un futur article, nous approfondirons la question, en évoquant d’autres sujets comme <code>PYTHONPATH</code>, le fichier <code>requirements.txt</code> ou des outils comme <code>poetry</code> ou <code>pipenv</code>. À suivre.</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn:1">
<p>C’est une condition suffisante, mais pas nécessaire - on y reviendra. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:1">↩︎</a></p>
</li>
<li id="fn:2">
<p>Presque. Il peut arriver que l’utilisateur courant ait les droits d’écriture dans <em>tous</em> les segments de <code>sys.path</code>, en fonction de l’installation de Python. Cela dit, c’est plutôt l’exception que la règle. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:2">↩︎</a></p>
</li>
<li id="fn:3">
<p>Cela peut vous paraître étrange à première vue. Il y a de nombreuses raisons historiques à ce comportement, et il n’est pas sûr qu’il puisse être changé un jour. <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:3">↩︎</a></p>
</li>
<li id="fn:4">
<p>Presque. Parfois il faut installer un paquet supplémentaire, notamment sur les distributions basées sur Debian <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:4">↩︎</a></p>
</li>
<li id="fn:5">
<p>Je n’ai pas réussi à trouver une explication satisfaisante à ce choix des mainteneurs Debian. Si vous avez des informations à ce sujet, je suis preneur. <em>Mise à jour: Il se trouve que cette décision s’inscrit au sein de la “debian policy”, c’est à dire une liste de règles que doivent respecter tous les programmes maintenus par Debian.</em> <a class="footnote-backref" href="https://dmerej.info/blog/fr/index.xml#fnref:5">↩︎</a></p>
</li>
</ol>
</div>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
    <entry>
        <title>Bonjour, monde</title>
        <link href="https://dmerej.info/blog/fr/post/bonjour-monde/" />
        <id>https://dmerej.info/blog/fr/post/bonjour-monde/</id>
        <updated>2019-05-05T13:08:25Z</updated>
        <content type="xhtml">
            <div xmlns="http://www.w3.org/1999/xhtml">
                <p>Bonjour à tous et bienvenue !</p>
<p>Cet article est le premier d’un tout nouveau blog (sur <a href="https://dmerej.info/blog/fr)">https://dmerej.info/blog/fr)</a>, contenant exclusivement des articles en français.</p>
<p>Notez l’existence de mon blog anglophone, qui est disponible sur
<a href="https://dmerej.info/blog">https://dmerej.info/blog</a>. Pour l’instant, les deux blogs sont complémentaires:
aucun article n’est la traduction directe d’un autre, mais
cela pourra changer un jour, qui sait ?</p>
<p>Sans plus attendre, vous pouvez lire mon <a href="https://dmerej.info/blog/fr/post/bibliotheques-tierces-python/">premier article sur Python et les bibliothèques tierces</a>.</p>
            </div>
        </content>
        <author>
            <name>Le blog de Dim&#39;</name>
        </author>
    </entry>
</feed>