MakeMake The Dwarf Planet is a feed agregator.

EuroPython - Calls for Proposals Closes Soon

by clytaemnestra from AFPy discuss

Hello everyone!

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.

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: Call for Proposals | EuroPython 2025 | July 14th-20th 2025 | Prague, Czech Republic & Remote.

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: https://forms.gle/JqG9Pks5KxDsxToi9.

We can’t wait to see you at EuroPython!

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Sur Lyon − Meetup le 29 janvier

by grewn0uille from AFPy discuss

Hello tout le monde !

Pour ce premier meetup de 2025 à Lyon, on se retrouve le mercredi 29 janvier dans les locaux de Malt (Bellecour) à 19h.

Carmen nous parlera d’optimisation des requêtes SQL dans Django et SQLAlchemy.

Pour les personnes que ça intéresse, les meetup Python ont maintenant leur compte Mastodon : Python Lyon (@python_lyon@piaille.fr) - Piaille.

Optimisation des requêtes SQL dans Django et SQLAlchemy : le problème N+1

2025-01-29 19:00 (Europe/Paris) → 2025-01-29 21:00 (Europe/Paris)

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Linux Mint : améliorer votre terminal ZSH avec l’auto-suggestion et la coloration syntaxique

by Olivier Pons from Olivier Pons

Comment améliorer votre terminal ZSH avec l’auto-suggestion et la coloration syntaxique

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.

Prérequis

  • ZSH installé comme shell par défaut
  • Git installé sur votre système
  • Droits d’accès à votre répertoire personnel

Installation des plugins

Commençons par créer un dossier dédié pour nos plugins ZSH et clonons les dépôts nécessaires :

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

Configuration

1. Activation des plugins

Ajoutez ces lignes à votre fichier ~/.zshrc pour activer les plugins :

source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

2. Mise à jour de la liste des plugins

Si vous utilisez Oh My Zsh, modifiez la ligne des plugins dans votre fichier ~/.zshrc :

plugins=(git thefuck poetry zsh-autosuggestions zsh-syntax-highlighting)

Fonctionnalités

Auto-suggestions

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 ➡ (flèche droite).

Coloration syntaxique

zsh-syntax-highlighting colore vos commandes en temps réel :

  • Commandes valides en vert
  • Commandes invalides en rouge
  • Options et arguments en couleurs distinctes
  • Chemins de fichiers existants soulignés

Conclusion

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.

Conseils bonus

  • Redémarrez votre terminal ou exécutez source ~/.zshrc pour appliquer les changements
  • Vous pouvez personnaliser les couleurs et le comportement des plugins en consultant leur documentation respective sur GitHub
  • Ces plugins sont compatibles avec la plupart des frameworks ZSH comme Oh My Zsh et Prezto

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 !

Lire la suite…

Traducteur professionnel dispo

by DMorandi from AFPy discuss

Bonjour,
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…
A+
Didier

3 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

SCAM ; publier un livre en organisant ses pensées

by Jul from Linuxfr.org

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

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 »

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 _^ (à bas la tyrannie de la PEP8, vive Perl, vive python)

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),

Puis ce fût un logiciel de microblogging (à la mode d'une tribune de linuxfr) pour illustrer comment utiliser HTML as a model,

Puis ce fût un organisateur d'idées (mind mapper).

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

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.

C'est en codant n'importe quoi, qu'on fait n'importe quoi.

projet
manuel du projet fait avec le projet

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

copie des fichiers d'un répertoire

by mapommfj from AFPy discuss

Bonjour,
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:
subprocess.call(['gnome-terminal', '--','sudo', '-S', 'cp','-v', path_src+"/nom1.py", path_src+"/nom2.html", path_src+"/nom3.sh", path_dest]) fonctionne correctement mais je voudrais ne pas lister tous les fichiers, donc j’ai essayé:
subprocess.call(['gnome-terminal', '--','sudo', '-S', 'cp','-v', path_src+"/*", path_dest]) qui ne fonctionne pas. Merci de me dire pourquoi ?

11 messages - 3 participant(e)s

Lire le sujet en entier

Lire la suite…

Commandes à exécuter pour installer Chrome sur une nouvelle installation Linux Mint

by Olivier Pons from Olivier Pons

Comment installer Google Chrome sur Linux (Ubuntu/Debian) – Guide complet

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.

Étapes d’installation détaillées

  1. Créer le dossier pour les clés de sécurité
    Cette étape permet de préparer le système pour stocker les clés de sécurité Google.
  2. Télécharger et installer la clé Google
    Nous récupérons la clé officielle de Google pour garantir l’authenticité des paquets.
  3. Ajouter le dépôt Chrome
    Configuration du dépôt officiel dans votre système pour accéder aux paquets Chrome.
  4. Mettre à jour la liste des paquets
    Actualisation de votre système avec le nouveau dépôt ajouté.
  5. Installer Chrome
    Installation finale du navigateur sur votre système.

Commandes à exécuter

Copiez et collez ces commandes une par une dans votre terminal :

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

Vérification de l’installation

Une fois l’installation terminée, vous pouvez :

  • Lancer Chrome depuis votre menu d’applications
  • Ou utiliser la commande google-chrome dans le terminal

En cas de problème lors de l’installation, assurez-vous d’avoir les droits administrateur et que votre système est à jour.

Lire la suite…

[Stage 6 mois - Développement logiciel] - Connexion d'une base de données géographique à une suite logicielle webmapping

by makina from AFPy discuss

Le contexte

Geotrek est une suite logicielle webmapping 100% libre dédiée à la gestion et à la valorisation des sentiers et activités outdoor pour les territoires publics (Parcs naturels régionaux, Parcs nationaux, départements etc).

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

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.

Découvrez quelques uns de nos projets et retrouvez-nous sur Welcome to the Jungle.

La mission

Vous interviendrez au sein d’une équipe pluridisciplinaire composée notamment de développeurs front end et back end, d’experts SIG, et sous leur responsabilité vous aurez pour mission de conduire le projet de la phase d’exploration à la phase de livraison :

  • 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 ;

  • 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 ;

  • Réalisation : mettre en place l’architecture technique de la solution, réalisation de tests unitaires ;

  • 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é.

Profil

Vous préparez un Bac+5 en informatique et 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, idéalement avec le framework Django.

Vous êtes familier avec le concept d’API REST et le protocole HTTP.

Vous êtes autonome et curieu.se, et aimez proposer des solutions. Le développement cartographique vous intéresse.

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.

Informations complémentaires

Pourquoi faire votre stage chez nous ?

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…).

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 !

É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. N’hésitez pas à nous montrer votre code si ça vous dit !

Plus d’informations sur notre processus de recrutement :

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 :

  • 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 ;
  • 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.

La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

[Stage 6 mois - Développement logiciel] - Création d'une interface d'administration d'un outil de valorisation des sentiers et activités outdoor

by makina from AFPy discuss

Makina Corpus développe des projets web ou mobiles d’envergure 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…

Notre organisation et nos prestations se construisent sur trois piliers : 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.

Découvrez quelques uns de nos projets et retrouvez-nous sur Welcome to the Jungle.

Le contexte

Geotrek est une suite logicielle webmapping 100% libre 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 Geotrek-Rando, un site Internet promotionnel pour des visiteurs du territoire.

L’objectif du stage 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 json, .html 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.

La mission

Vous interviendrez au sein d’une équipe pluridisciplinaire composée notamment de développeurs front end et back end, d’experts SIG, et sous leur responsabilité vous aurez pour mission de conduire le projet de la phase d’exploration jusqu’à la phase de livraison :

  • 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 ;

  • 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 ;

  • Réalisation : mettre en place l’architecture technique de la solution, implémentation, développement logiciel ;

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

Profil

Vous préparez un Bac+5 en informatique et possédez une bonne compréhension de la structure d’une application en JavaScript. Vous avez une première expérience :

  • Sur une bibliothèque ou un framework populaire tel que React, Vue ou Angular ;
  • Avec le fonctionnement du HTML/CSS/DOM ;
  • Sur API REST ;
  • En bases en versioning avec Git, GitHub et les processus classiques de développement en équipe.

Savoir réaliser des interfaces graphiques (UI/UX) serait un plus.

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.

Informations complémentaires

Pourquoi faire votre stage chez nous ?

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…).

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 !

É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. N’hésitez pas à nous montrer votre code si ça vous dit !

En savoir plus sur notre processus de recrutement :

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 :

  • 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 ;
  • 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.

La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Chef-Cheffe de projets web junior : climat, agriculture et environnement

by makina from AFPy discuss

Rejoignez Makina Corpus 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.

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

Découvrez quelques uns de nos projets, et retrouvez-nous sur Welcome To The Jungle.

La mission

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.

Vos missions consisteront à :

  • Identifier et mettre en œuvre au sein du projet les besoins technico-fonctionnels des clients ;
  • Formaliser, organiser, planifier et contrôler les phases de réalisation ;
  • Piloter et coordonner l’équipe projet ;
  • Assurer le suivi du planning et le contrôle de la qualité ;
  • Gérer les engagements vis-à-vis du client et s’assurer de sa satisfaction ;
  • Fidéliser, entretenir et développer le portefeuille client existant ;
  • Participer aux phases d’avant-vente en relation avec le client et avec nos équipes, rédiger une proposition commerciale.

Nous mettrons en place un plan de formation et un accompagnement par plusieurs chefs de projets 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.

Ce poste est ouvert au télétravail partiel (jusqu’à 3 jours/semaine).

Profil

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. Vous avez une appétence commerciale et idéalement une expérience dans la réponse à appels d’offres.

  • Vous aimez comprendre les besoins du client, s’approprier son métier et lui proposer des solutions adaptées ;
  • Vous possédez un background technique dans le développement web ;
  • Votre goût du travail en équipe, votre curiosité, vos excellentes qualités relationnelles seront des atouts indispensables. Apprendre toujours plus vous stimule !

Nous ne précisons pas de diplôme ou de niveau d’études minimum car nous attachons avant tout de l’importance aux compétences et à la passion du métier.

Informations complémentaires

Dans la ruche collaborative Makina Corpus, on dit ce qu’on fait : 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…).

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 ! Nos équipes sont mixtes, femmes et hommes du numérique nous vous attendons.

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

En savoir plus sur notre processus de recrutement :

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 :

  • 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 ;
  • 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 ;
  • enfin, vous serez reçu.e par le responsable de l’agence.

La décision finale sera prise collectivement par vos différents interlocuteurs. Tout le long du parcours, vous serez en lien direct avec Lise.

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Pycon Austria 2025 - invitation

by horstjens from AFPy discuss

Mesdames et Messieurs,
Je voudrais vous inviter chaleureusement à Pycon Autriche 2025.

Malheureusement, mon français n’est pas assez bon pour le reste du message, je vais donc écrire en anglais:

Please share the following message among your members:

There will be a free international Python conference in Austria from 6th to 7th April 2025:
https://at.pycon.org

(conference language will be English)

Entrance is for free but registration as a visitor, volunteer or speaker is necessary. Please register now because our places are limited.

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.
Would you be interested to represent your group with a table (or a poster / booklets / advertising material) at the conference ?
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.
Also, if possible, could you please spread the message about the conference and print out and publish this poster :
https://drive.google.com/drive/folders/1peXO4pThfR289gb1hpT4Elq-hVodoMtT

greetings from Vienna,
-Horst JENS

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Problème permission zsh

by sg72 from AFPy discuss

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

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)

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.

La version python installée sur l’ordinateur est la version 2.7.16

11 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Placement de widget

by mapommfj from AFPy discuss

Bonjour,
sujet certainement trivial mais je ne comprends pas la différence entre:

lab1=Label(fen1, text = "label dans fen1", bg='bisque', font=("Verdana", 10))
lab1.place(x=xl, y=yl)

et
lab1=Label(fen1, text = "label dans fen1", bg='bisque', font=("Verdana", 10)).place(x=xl, y=yl)
je n’ai pas trouvé d’explication mais c’est sûr il y a une différence de fonctionnement :slightly_smiling_face:

7 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

La galère de Python en déploiement

by abriotde from Linuxfr.org

Sommaire

Dans un lien 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.

Un peu d'histoire

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

Les langages interprétés

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.

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é.
Bash étant quasiment immuable (on peut parfois le déplorer), on a rarement des problèmes de ce type (Mais bien d'autres ;) ).
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…
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.
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.

Un cas concret: le miens

Je développe OpenHEMS, 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'Emhass 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) : Olinuximo. Seulement, OLinuXino ne propose que Debian 11 (C'est maintenu mais pas le dernier) et avec je n'ai que Python 3.9.
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é.
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.

Ma solution : Docker

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).
Avec Docker OpenHEMS est beaucoup plus simple tester.
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:
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.
2. Les logs étaient directement écris dans le /var/log/openhems, il faut un montage (Mais j'ai encore des problèmes là).

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…

PS : Peut-être n'ais-je pas fait les meilleurs choix. Je suis ouvert aux réflexions en commentaires.

En langage compilé

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

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

UV un énième packageur python

by barmic 🦦 from Linuxfr.org

On se moque facilement des projets js qui vont et qui viennent mais python n’est pas en reste avec ses toolchains. 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 python -m pip install requests ne me vient pas du premier coup).

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.

Bon il s’avère que j’étais sur un petit outil en python donc essayons la doc d’installation :

curl -LsSf https://astral.sh/uv/install.sh | sh

(Quand je vais leur raconter ça sur linuxfr, faudra que ce soit un vendredi.)

Et l’usage ?

  • créer un projet ? uv init dossier
  • ajouter une dépendance ? uv add ma-super-bibliothèque
  • lancer mon projet ? uv run mon-script.py

Ok c’est rapide ça utilise un environnement virtuel, ça m’a créé quelques fichiers

  • pyproject.toml
  • uv.lock
  • .env/
  • .python-version

Ouai je vois bien à quoi sert chaque fichier.

Au final pour mon usage simple ça fait le job très bien. Je ne sais pas s’il peut servir à créer des wheel 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 pip et les commandes sont simples à mémoriser.

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant l'automne 2024

by Éloi Rivard <eloi@yaal.coop> from Yaal

Mécénat

Pygments

Bibliothèque Python de coloration syntaxique

Pluralizefr

Bibliothèque Python pour obtenir un mot au pluriel à partir du singulier

PSPSDK

Ensemble d'outils et de bibliothèques pour la console PSP de Sony

apt-setup

Partie de Debian-Installer. Produit un fichier /etc/apt/sources.list pour le système installé

bmg

Déplace un fichier (ou répertoire) pendant 3 minutes. Une fois le délai expiré, le fichier (ou répertoire) revient.

Principalement :

Canaille

Serveur d’identité et d'autorisations ultra-léger

Nous avons publié 1 nouvelle version durant cette saison.

scim2-models

Sérialisation et validation de ressources SCIM avec Pydantic

Nous avons publié 11 nouvelles versions durant cette saison.

scim2-server

Prototype de server SCIM2 ultra-léger

Nous avons publié 1 nouvelle version durant cette saison.

scim2-client

Fabrication et analyse pythonique de requêtes SCIM

Nous avons publié 12 nouvelles versions durant cette saison.

scim2-tester

Outil de vérification de conformité de serveurs aux normes SCIM

Nous avons publié 8 nouvelles versions durant cette saison.

scim2-cli

Outil en ligne de commandes pour interagir avec des applications SCIM

Nous avons publié 3 nouvelles versions durant cette saison.

wtforms

Bibliothèque python de gestion de formulaires web

Nous avons publié 2 nouvelles versions durant cette saison.

flask-wtf

Intégration de WTForms dans Flask

Nous avons publié 1 nouvelle version durant cette saison.

wtforms-sqlalchemy

Intégration de SQLAlchemy dans WTForms

Nous avons publié 1 nouvelle version durant cette saison.

click

Boîte à outil pour créer des programme en ligne de commande composables avec Python

jinja-autodoc

Documentation automatique des patrons Jinja avec Sphinx

Nous avons publié 3 nouvelles versions durant cette saison.

Lire la suite…

Autumn 2024 FOSS contributions from by the Yaal Coop team

by Éloi Rivard <eloi@yaal.coop> from Yaal

Sponsoring

Pygments

Pygments is a generic syntax highlighter written in Python

Pluralizefr

Python library to get plural word from singular one

PSPSDK

Collection of tools and libraries written for Sony's Playstation Portable (PSP) gaming console

apt-setup

Part of Debian-Installer. Generate an /etc/apt/sources.list for the installed system

bmg

It moves a file (or directory) for 3 minutes. At the time out, the file (or directory) comes back.

Mainly:

Canaille

Lightweight identity and authorization management software

We published 1 release during this season.

scim2-models

SCIM resources serialization and validation with Pydantic

We published 11 releases during this season.

scim2-server

Lightweight SCIM2 server prototype

We published 1 release during this season.

scim2-client

Pythonically build SCIM requests and parse SCIM responses

We published 12 releases during this season.

scim2-tester

SCIM RFCs server compliance checker

We published 8 releases during this season.

scim2-cli

SCIM application development CLI

We published 3 releases during this season.

wtforms

A flexible forms validation and rendering library for Python.

We published 2 releases during this season.

flask-wtf

Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.

We published 1 release during this season.

wtforms-sqlalchemy

WTForms integration for SQLAlchemy

We published 1 release during this season.

click

Python composable command line interface toolkit

jinja-autodoc

Automatically document your Jinja templates with Sphinx

We published 3 releases during this season.

Lire la suite…

Nouvelles fonctionnalités de sécurité implémentées dans Canaille

by Sébastien Birolleau <sebastien@yaal.coop> from Yaal

Nous avons travaillé récemment sur les principales caractéristiques de sécurité de Canaille, dans le cadre de notre subvention NLNet.

Sécurité

Au cours de ce sprint, nous nous sommes concentrés sur la mise en œuvre des recommandations de sécurité conseillées par l'agence publique française de cybersécurité "ANSSI".

Authentification multifactorielle

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.

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.

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 :

Les méthodes HOTP/TOTP exigent que l'utilisateur télécharge et configure une application mobile ou un logiciel d'authentification (comme FreeOTP), 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.

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 SMTP. De même, un serveur SMPP fonctionnel est nécessaire pour la méthode SMS.

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.

Verrouillage anti-intrusion

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.

Journalisation des événements de sécurité

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.

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, etc.

Vérification de la compromission du mot de passe

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 Have I Been Pwned.

HIBP offre un point de terminaison API gratuit qui peut être consulté pour les mots de passe compromis.

Politique d'expiration des mots de passe

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.

Approvisionnement avec SCIM

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.

Grâce à nos récents travaux sur SCIM, 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.

Documentation

Internationalisation

Pour rendre Canaille plus accessible, nous avons passé du temps à rendre notre documentation traduisible. L'interface de traduction est disponible sur Weblate. Nous avons également traduit la documentation en français 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.

Habillage

Nous avons également travaillé sur la documentation sur la personnalisation de l'habillage de Canaille pour aider les utilisateurs à personnaliser l'apparence de leur instance Canaille. Nous souhaitions référencer et documenter tous nos patrons, pour aider les designers à les modifier. Pour y parvenir, nous avons dû transformer une ancienne bibliothèque non maintenue en une nouvelle bibliothèque jinja-autodoc 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 sphinx-contrib.

Lire la suite…

New security features implemented in Canaille

by Sébastien Birolleau <sebastien@yaal.coop> from Yaal

We have been working recently on key security features for Canaille, as parts of our NLNet grant.

Security

During this sprint we focused on implementing security recommandations advised by the French cybersecurity public agency "ANSSI".

Multi-factor Authentication

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.

The solution was found in asking users to authenticate themselves using two or more authentication methods, or factors - hence the name multi-factor authentication.

For an identity management software like Canaille, this was a key feature to have, and we implemented it for four different methods:

The HOTP/TOTP methods require the user to download and set up an authenticator mobile app or software (like FreeOTP), 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.

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 SMTP server. Likewise, a functioning SMPP server is needed for the SMS method.

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.

Intruder lockout

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.

Security events logging

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.

Logged security events include authentication attempts, password or email updates, emission or revokation of OAuth tokens, and more.

Password compromise investigation

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 Have I Been Pwned's API.

HIBP offers a free API endpoint that can be consulted for compromised passwords.

Password expiry policy

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.

Provisioning with SCIM

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.

Thanks to our recent work on SCIM 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.

Documentation

Internationalization

To make Canaille more accessible, we spent some time to make our translation translatable. The translation interface is available on Weblate. We also translated the documentation in French to validate the mechanism. This was also an opportunity for us to review all the existing documentation and fix wording errors and typos.

Theming

We also have worked on the theming documentation to help users customize how their Canaille instance looks. We wanted to reference and document all our templates, to help designers modify them. To achieve this we had to fork an old unmaintained library into a new library jinja-autodoc for automatic template documentation generation. We cleaned it, made a few improvements, and pushed it under the sphinx-contrib organization.

Lire la suite…

CDI Dev Odoo / Python - Coopérative Commown à Strasbourg

by Adrien-Commown from Linuxfr.org

Notre coopérative :

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.

Plus qu’une simple coopérative de location, Commown :

  • 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, voir cet article;
  • Soutient les producteurs responsables : achats, soutien de marketing, relai de services, financement de R&D ;
  • Crée et gère des biens communs comme notre logiciel libre de gestion des locations de longue durée publié sur notre GitHub
  • 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.

Vos missions :

Au siège de Commown à Strasbourg, vous rejoindrez l’équipe Outils informatiques et vous contribuerez :

  • Au développement du système de gestion et à l’amélioration des outils internes
  • À la consolidation des systèmes en production et à la sûreté des données

Ainsi, vous pourrez travailler sur :

  • 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)
  • Intégration de modules OCA pour nos besoins fonctionnels par encore ou mal couverts : assemblage, logistique, réparation…
  • Développement de nouveaux modules pour nos besoins spécifiques (ergonomie, interaction avec d’autres services, extension de nos activités…)
  • Maintenance fonctionnelle et corrective de nos modules actuels
  • Migration vers les nouvelles versions Odoo (tous les 3 ans environ)
  • 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.
  • 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.
  • 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

Nous recherchons une personne qui :

  • À un intérêt marqué pour ce type de projet : écologique, éthique, coopératif, bien commun (logiciel libre)
  • S’intègre facilement dans une équipe et communique bien avec les autres
  • À une bonne capacité d’abstraction et de modélisation de connaissances variées
  • Aime comprendre de manière approfondie les sujets techniques
  • Favorise la logique et la connaissance dans la résolution de problèmes
  • Aime aller au bout des choses : rendre des travaux terminés, fonctionnels, bien testés et documentés, pensés pour la maintenance future
  • Sait apprendre en permanence, par la veille, la lecture, la réflexion méthodologique
  • Cherche un emploi en phase avec ses valeurs

Compétences idéales

  • Bonne connaissance du fonctionnement du web (protocoles, back et front)
  • Connaissance théorique et pratique du langage python et de sa librairie standard
  • Pratique fluide de git ou mercurial dans un contexte de travail collectif
  • Maîtrise élémentaire du shell posix
  • Notions et un peu d’expérience pratique de l’administration-système sous Linux
  • Idéalement expérience d’interaction avec des communautés du logiciel libre

Modalités

NB 1 : 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 !

NB 2 : 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.

NB 3 : Lieux de travail : Strasbourg, full distanciel possible à terme

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

Retours sur les meetups en mixité choisie

by grewn0uille from AFPy discuss

Au cours de la saison de meetups dernière, on avait organisé des meetups en mixité choisie sur Lyon.

@tut-tuuut 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 : Rencontres en non-mixité choisie : retour d’expérience et mise en perspective — 24 jours de web

2 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Livrer un environnement Python

by gUI from Linuxfr.org

Bonjour,

Si je développe un truc en Python, je peux faire les choses proprement en me faisant un environnement virtuel (j'aime bcp venv). Ensuite avec un pip freeze j'ai ma liste des packages.

Bon, mais si quelqu'un désire utiliser mon travail, il va devoir se recréer un environnement virtuel, y faire son pip install, le sourcer puis ensuite exécuter mon code.

Est-ce qu'il existerait un truc plus immédiat, à la appimage, où tu peux tout empaqueter prêt à l'emploi ?

Merci !

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

uv : guide complet du nouveau gestionnaire de packages Python rapide et ambitieux

by Camille Roux from Human coders

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.


Commentaires
L'article uv : guide complet du nouveau gestionnaire de packages Python rapide et ambitieux a été posté dans la catégorie Python de Human Coders News

Lire la suite…

Boîte à outils SCIM en Python

by Éloi Rivard <eloi@yaal.coop> from Yaal

Nos copains d’IndieHosters proposent à leurs utilisateurs un catalogue de services é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.

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 :

  • je crée mon compte utilisateur auprès de Keycloak (par exemple, en remplissant un formulaire d’inscription),
  • je tente d’accéder à Nextcloud, mais je n’ai pas de session ouverte, je suis donc redirigé vers Keycloak,
  • je m’identifie, Keycloak génère un jeton contenant mes informations personnelles,
  • ce jeton est transmis à Nextcloud,
  • 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.
  • Nextcloud m’autorise enfin l’accès aux fichiers.

C’est très pratique, mais ça ne couvre pas tous les cas de figure :

  • 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.
  • 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.
  • Comment supprimer ou désactiver un compte utilisateur auprès de tous les services ?

Pour effectuer toutes ces opérations, on utilise un protocole de provisionnement. Provisionner 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 SCIM. IndieHosters a préparé une page web d’explications sur le protocole que l’on vous invite à consulter.

IndieHosters a obtenu un financement auprès de NLNet 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 :

  • 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:
    • scim2-models, une bibliothèque Python de sérialisation et validation de ressources SCIM. Elle est basée sur Pydantic 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.
    • scim2-client, une bibliothèque Python de fabrication et d’analyse pythonique de requêtes SCIM. Elle s’appuie sur scim2-models et sur httpx pour créer des requêtes SCIM, et analyser les réponses des serveurs.
    • scim2-server, un prototype de serveur SCIM développé par CONTACT Software utilisant scim2-models, et co-maintenu par Yaal Coop.
    • scim2-tester, 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.
    • scim2-cli, 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.
  • Proposer l’adoption de SCIM comme protocole officiel de provisionnement dans le protocole de messagerie instantanée Matrix. Nous avons rédigé une proposition d’évolution de la norme (MSC4098), 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.
  • Conjointement à la proposition d’évolution de la norme, nous avons proposé une implémentation de SCIM dans synapse, le serveur Matrix le plus utilisé actuellement. L’implémentation se base sur scim2-models.

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

Lire la suite…

Python SCIM toolbox

by Éloi Rivard <eloi@yaal.coop> from Yaal

Our friends from IndieHosters provide a rich catalog of services 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.

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.

  • the users create their account against Keycloak (for instance by filling a subscription form),
  • they try to access Nextcloud, but they have no open session, so they get redirected to Keycloak,
  • they log in, Keycloak generates a token containing their personal information,
  • this token is forwarded to Nextcloud,
  • 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.
  • Nextcloud finally gives access to the user.

This is convenient, but this does not cover all the use cases:

  • 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.
  • Users edit their personal information on the identity server (for instance, their display name). How to instantly spread the modification on all the services? Currently, personal information are only updated when users log-in anew on the services.
  • How to delete or deactivate user accounts on all the services, once they have been created?

To achieve all those operations, it is needed to use a provisioning protocol. Provisioning is the action of forwarding objects (often user and groups) modifications between several services. These days, the industry standard is SCIM. IndieHosters started a nice presentation webpage about SCIM.

They obtained a NLNet grant to develop SCIM in the ecosystem of their tools, and hired Yaal Coop for a part of the project. We had several missions:

  • 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:
    • scim2-models, a SCIM resources validation and serialization Python library. It relies on Pydantic, provides native objects that implement the SCIM specification. It aims to be used as a building block for SCIM server and client applications.
    • scim2-client, a Python library that creates and validates SCIM network requests. It uses httpx to handle the network part.
    • scim2-server, a SCIM server prototype that uses scim2-models developped by CONTACT Software, and co-maintained by Yaal Coop.
    • scim2-tester, 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.
    • scim2-cli, a command line utility that uses scim2-client and scim2-tester, and provides an interface to perform various operations on SCIM servers.
  • Discuss the adoption of SCIM as the official provisioning protocol for the instant messaging protocol Matrix. We redacted an evolution request for the protocol (MSC4098), 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.
  • In parallel, we developed a SCIM implementation in synapse, the most famous Matrix server currently. The implementation uses scim2-models.

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

Lire la suite…

Surveiller si fichier modifié par d'autres programmes

by bul from AFPy discuss

bonjour à tou[te]s

petit souci dans le script :

#!/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)

je tente de surveiller si un fichier est modifié par un autre programme
( pour le test, le script lui-même )
si je place le contrôle dans le corps du programme,
aucune réaction, alors qu’au lancement, ça marche
dans mon application j’ai besoin de mettre cette
surveillance “en dynamique”, au fur et à mesure
on peut faire comment ?
merci d’avance

6 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Stage - Développement web (Gap)

by camille_monchicourt from AFPy discuss

Le Parc national des Écrins recherche un·e stagiaire en développement web (Python, #Flask, django, #Javascript, #Typescript, #PostgreSQL, #PostGIS, #OpenSource : [STAGE] Développement web (Python, javascript, PostGIS) | Parc national des Ecrins

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.

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Sur Lyon − Meetup le 19 décembre

by grewn0uille from AFPy discuss

Hello tout le monde,

Meetup de fin d’année le jeudi 19 décembre, dans les locaux de Lowit (métro Part-Dieu) !

Comme l’an dernier, on vous propose un format Lightning Talks :christmas_tree:

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 :slight_smile:

Lightning Talks de Noël 🎄

2024-12-19 19:00 (Europe/Paris) → 2024-12-19 21:30 (Europe/Paris)

4 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Effacer terminal

by mapommfj from AFPy discuss

Bonjour, encore une petite question de néophyte, désolé:
j’ai un script qui ouvre (à travers une combo) un terminal où se déroule un script python3. Cela donne:

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

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.
J’avais essayé un bouton avec subprocess.run("clear", shell=True), mais cela ne donne rien.
Auriez-vous une piste ? Merci d’avance

8 messages - 3 participant(e)s

Lire le sujet en entier

Lire la suite…

Idées de talk pour les meetups

by vpoulailleau from AFPy discuss

Salut,

Je discutais par mail avec Reuven Lerner, un habitué des conférences Python internationales (PyVideo.org).

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.

Je vous mets un bout du mail (en anglais…)

Here are a few types of conference/meetup talks that could be interesting:

  1. How does ___ work behind the scenes?

Assignment. Dictionaries. Lists. Importing modules. Grouping in Pandas.
Functions. This is one of my favorite things to do, because it has
almost infinite depth, and you’ll surprise yourself with what you find
in preparing such a talk.

  1. ___ has changed in Python, and I’ll tell you about it

PyArrow in Pandas. Dictionaries (a while ago). Sorting (very recently).
f-strings. case-match.

  1. You think that ___ is complicated. I’m going to simplify it for you.

Decorators. Comprehensions.

  1. Here’s a cool thing that I did in Python. I’ll show it to you, and
    tell you what I learned along the way.

  2. Weird and surprising stuff.

Qu’en pensez-vous ?

3 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Tremplin MiXiT 2025

by grewn0uille from AFPy discuss

Hello tout le monde,

Le MiXiT et CraftRecords retravaillent ensemble pour l’édition 2025 du MiXiT et proposent un tremplin.

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.

Cette année, uniquement des sujets techniques sont recherchés.

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.
Les deux conférences ayant le plus de voix seront sélectionnées pour le MiXiT !

Si vous êtes sur Lyon ou alentours, n’hésitez pas à postuler (en plus les coachs sont trop sympas :stuck_out_tongue:)

:date: Date limite pour postuler : 22 décembre 2024
:studio_microphone: Meetup de sélection : 26 mars 2024
:muscle: Équipe de coachs : Léa Coston, Yann Bouvet, Houleymatou Baldé, Antoine Caron, @liZe et moi-même
:arrow_right: Formulaire d’inscription : Inscription Tremplin Mixit 2025

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Afficher une fenêtre de notification depuis le shell

by ascendances from ascendances

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.

Notify-send

notify-send est disponible dans le paquet libnotify-bin (dans Debian et ses dérivées) et est probablement déjà installé. La capture montre le rendu avec Gnome. La commande :

$ notify-send "ici un titre" "ici le contenu"

Zenity

zenity 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 :

$ zenity --info --title="ici un titre" --text="ici un contenu" --timeout=5

Kdialog

Notification avec kdialog

kdialog fait partie de KDE. Le type passivepopup est une notification qui apparaît dans un coin du bureau et disparaît automatiquement :

$ kdialog --passivepopup --title "ici un titre" "ici un contenu"

Xmessage

xmessage fait partie d’outils fournis avec X11 (paquet x11-utils 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.

$ xmessage -timeout 5 "ici un contenu"

Versions utilisées

Le rendu des captures d’écran peuvent différer selon la version des logiciels utilisés. Les captures ont été faites avec :

  • Gnome 47
  • KDE Plasma 5.27
  • Zenity 4.0.2
  • Xmessage 1.0.7

Lire la suite…

affichage label

by mapommfj from AFPy discuss

Bonjour,
voici la structure de mon programme:

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()

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.

3 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Django : Optimiser les performances pour la production

by Camille Roux from Human coders

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.


Commentaires
L'article Django : Optimiser les performances pour la production a été posté dans la catégorie Python de Human Coders News

Lire la suite…

Et hop, un nouvel exercice sur HackInScience : les carrés magiques

by mdk from AFPy discuss

TL;DR : HackInScience — Magic Square

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à exercises/magic-square · main · hackinscience / hkis-exercises · GitLab).

Oui je sais j’avais déjà quelque chose autour des carrés magiques (HackInScience — Dirichlet solver) mais celui-ci est beaucoup plus simple.

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 » :slight_smile:

Si vous avez des idées d’exos je prends !

11 messages - 5 participant(e)s

Lire le sujet en entier

Lire la suite…

Utilisation de pybind11

by Mindiell from AFPy discuss

Coucou ici,

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.

Mais quoi que je fasse, j’obtiens toujours une erreur “undefined symbol”.

Quelques infos :

  • La librairie compile bien, en dynamique ou en statique.
  • j’ai réussi à générer les exemples donnés par pybind11 dans leur tutoriel (les premiers pas quoi)
  • la commande que j’utilise pour compiler est un poil complexe :

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)

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.

La compilation se passe bien, mais si j’importe le résultat :

>>> import example
ImportError: /[...]/sfml/example.cpython-312-x86_64-linux-gnu.so: undefined symbol: _ZNK2sf4Time9asSecondsEv

Il ne trouve donc ps le symbole sf::Time.asSeconds.

Tout idée est la bienvenue :slight_smile:

5 messages - 3 participant(e)s

Lire le sujet en entier

Lire la suite…

Python dans org-mode avec des tables en entrée et en sortie

by mdk from AFPy discuss

On en parlait avec @Merwyn pendant la PyConFR, mais une démo vaut mieux que démo^Wdes mots :

D’abord ça nécessite un peu de config :

(org-babel-do-load-languages
 'org-babel-load-languages
 '((python . t)))

puis dans un fichier 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`.

J’entends d’ici les gens râler sur ma virgule après for hostname, haha.

Bon pas besoin de sortir Python pour juste un ping :

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

D’ici à lancer mes playbooks Ansible depuis org-mode y’a qu’un pas…

1 message - 1 participant(e)

Lire le sujet en entier

Lire la suite…

Documentation multi langue alabaster

by yabb85 from AFPy discuss

Bonjour,

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.
Savez-vous comment ajouter un moyen de passer d’une langue a l’autre dans la documentation générée?
Merci

3 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Rapport de transparence de la PyConFR 2024

by grewn0uille from AFPy discuss

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 31 octobre au 3 novembre à Strasbourg, rassemblant des personnes de la communauté Python. Les participantes et participants à la conférence sont tenues de respecter ​le Code de Conduite de l’Association Francophone Python, l’association qui organise l’événement.

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.

Télécharger le rapport en PDF (FR/EN)

2 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Sur Bordeaux − Meetup le 11 décembre

by yoan from AFPy discuss

Salut,

Deuxième meetup de l’année au Node à bordeaux :partying_face:

Bordeaux Python Meetup 2024.2

2024-12-11 18:30 (Europe/Paris) → 2024-12-11 20:30 (Europe/Paris)

10 messages - 5 participant(e)s

Lire le sujet en entier

Lire la suite…

Réunions du comité directeur 2024-2025

by entwanne from AFPy discuss

Ceci est le sujet lié à la réunion récurrente du comité directeur.
Celle-ci a lieu chaque mois le 3ème mardi à 20h30.

Les compte-rendus de réunions sont publiés sur notre dépôt git et le lien sera posté sur ce sujet après chaque réunion.

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.
Ces réunions sont aussi accessibles à toute personne qui en ferait la demande auprès du comité.

Réunion du comité directeur

2024-11-19 20:30 (Europe/Paris)

3 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

Version d'un programme AppImage

by mapommfj from AFPy discuss

Bonjour,
je cherche via un script a connaitre la version d’un logiciel externe de type AppImage. Y-aurait-il un moyen pour le faire ?
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.
Une idée serait la bienvenue, …si c’est possible…

19 messages - 2 participant(e)s

Lire le sujet en entier

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

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

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

La PyConFR 2024 démarre ce jeudi 31 octobre à Strasbourg, inscription obligatoire mais gratuite

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

the PyConFR 2024, taking place from October 31 to November 3 in Strasbourg. Registration is mandatory but free of charge.

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

la PyConFR 2024 se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

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"

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

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.

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

Plus que 10 jours avant la PyConFR 2024, se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite

Lire la suite…

Un jeu vidéo en encart de Jeux et Stratégies : Le Sceptre Maudit v0.2

by Julien Laumonier from Linuxfr.org

D'où ça vient ?

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.

sets-basic.gif

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 : https://gitlab.com/jlaumonier/sets-qb.git

Implémenter un jeu : le Sceptre Maudit

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.

Donc, je me suis mis au Python et j'ai commencé par "Le Sceptre Maudit" provenant du Jeux et Stratégies 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.

À 1 seul joueur :
sceptremaudit-v0.2-solo.gif

Et à plusieurs :
sceptremaudit-v0.2-2players.gif

La version 0.2 est disponible pour linux et win64 : https://gitlab.com/jlaumonier/encartgames/-/releases/v0.2. Le code source est disponible sous licence CC BY-SA-NC 4.0 sur gitlab : https://gitlab.com/jlaumonier/encartgames.git

Py MAS Engine Plateform

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.

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 architecture orientée domaine et bien sûr avec une architecture orientée agents. Pour cela, elle s'appuie sur des modèles théoriques comme le DEC-POMDP et les Graphes conceptuels. D'un point de vue technique, elle est basée sur pygame-ce et pygame-gui pour la partie affichage.

Elle est disponible comme paquet pypi et sur gitlab sous license MIT :

https://pypi.org/project/pymasep/

https://readthedocs.org/projects/pymasep/

https://gitlab.com/jlaumonier/pymasep

Pour un exemple d'utilisation de Pymasep avec une implémentation simple de l'algorithme Q-Learning sur le jeu de Chat et Souris : https://gitlab.com/jlaumonier/pymasep-examples

Cat/Mouse Qlearning

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.

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

Ce que j'ai appris en créant le backend Python pour YTO

by Matthieu Segret from Human coders

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.


Commentaires
L'article Ce que j'ai appris en créant le backend Python pour YTO a été posté dans la catégorie Python de Human Coders News

Lire la suite…

Comparaison des performances : Python 3.12 vs Python 3.13

by Camille Roux from Human coders

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


Commentaires
L'article Comparaison des performances : Python 3.12 vs Python 3.13 a été posté dans la catégorie Python de Human Coders News

Lire la suite…

Dernières nouvelles de FPDF2

by Lucas-C from Human coders

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.


Commentaires
L'article Dernières nouvelles de FPDF2 a été posté dans la catégorie Python de Human Coders News

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

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.

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

Plus que 17 jours avant la PyConFR 2024, se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite

Lire la suite…

écrire du code dans le corps d'une classe python

by jtremesay from Linuxfr.org

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.

Exemple :

import datetime

class MyClass:
    if datetime.datetime.now().isoweekday() == 5:
        current_day = "trolldi"
        for i in range(10):
            print("TODAY IS", current_day, "!!!!!!!!")
    else:
        current_day = "pas trolldi"

print("current_day:", MyClass.current_day)
$ 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

Voila, c'est tout. Bisous et bon weekend à tous !

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

Alexandre Astier code en Python

by rewind from Linuxfr.org

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»

Il sait vraiment tout faire ce gars, c'est assez exceptionnel.

Télécharger ce contenu au format EPUB

Commentaires : voir le flux Atom ouvrir dans le navigateur

Lire la suite…

Nouveautés de Python 3.13

by Matthieu Segret from Human coders

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.


Commentaires
L'article Nouveautés de Python 3.13 a été posté dans la catégorie Python de Human Coders News

Lire la suite…

Mon équipe idéale

by Le blog de Dim' from Le blog de Dim'

Introduction #

3 ans chez Arolla : un bilan #

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.

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.

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.

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.

À la recherche d’un nouvel emploi #

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.

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.

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.

Mon équipe idéale #

D’abord, elle assure la sécurité psychologique des personnes qui la compose:

  • 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.
  • 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é.
  • Elle prend le temps de bien faire les choses bien plutôt que de subir des pressions et de prendre des raccourcis.
  • Les personnes qui la composent prennent soin les unes des autres.

Ensuite, elle se repose sur l’intelligence collective :

  • Elle utilise une communication douce et positive, à la fois entre les membres et avec les autres équipes autour d’elle
  • Elle pratique la recherche du consensus et une certaine forme de démocratie interne
  • 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.
  • Ses membres travaillent régulièrement à plusieurs, que ce soit en binôme ou par petits groupes.
  • 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.

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.

Côté code (parce que je compte bien continuer à développer 😉 ) :

  • Les postes de travail sont agréables à utiliser, sans restrictions inutiles.
  • 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.
  • 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.
  • 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.

Conclusion #

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.

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 page de contact) - et n’hésitez pas à relayer cet article autour de vous.

Sinon, si cette vision vous semble trop idéaliste, alors le prendrai comme un compliment 😎.

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

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.

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

Plus que 24 jours avant la PyConFR 2024, se déroulant du 31 octobre au 3 novembre à Strasbourg, inscription obligatoire mais gratuite

Lire la suite…

Tout ce que vous devez savoir sur Python 3.13 – JIT et suppression du GIL

by Matthieu Segret from Human coders

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.


Commentaires
L'article Tout ce que vous devez savoir sur Python 3.13 – JIT et suppression du GIL a été posté dans la catégorie Python de Human Coders News

Lire la suite…

AFPy

by AFPy - Mastodon from AFPy - Mastodon

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.

Lire la suite…

Introduction à l'UX, présentation d'une présentation

by Brunélie Lauret <brunelie@yaal.coop> from Yaal

Expérience utilisateur, sensibilisation et périmètre

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.

On trouvait ça dommage de tout garder pour nous, alors c'est accessible à tous⋅tes !

La présentation, en format pages web, est accessible à tous⋅tes sur notre site à l'adresse https://yaal.coop/ux/index.html. 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.

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 !

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant l'été 2024

by Éloi Rivard <eloi@yaal.coop> from Yaal

Mécénat

Pygments

Bibliothèque Python de coloration syntaxique

PSPSDK

Ensemble d'outils et de bibliothèques pour la console PSP de Sony

apt-setup

Partie de Debian-Installer. Produit un fichier /etc/apt/sources.list pour le système installé

scim2-models

Sérialisation et validation de ressources SCIM avec Pydantic

scim2-client

Fabrication et analyse pythonique de requêtes SCIM

scim2-tester

Outil de vérification de conformité de serveurs aux normes SCIM

scim2-cli

Outil en ligne de commandes pour interagir avec des applications SCIM

scim2-server

Prototype de server SCIM2 ultra-léger

authlib

Bibliothèque python de gestion des identités et des accès

synapse

Serveur Matrix écrit en Python/Twisted

pydanclick

Ajoutez des options Click à partir de modèles Pydantic

canaille

Serveur d’identité et d'autorisations ultra-léger

Lire la suite…

Summer 2024 FOSS contributions from by the Yaal Coop team

by Éloi Rivard <eloi@yaal.coop> from Yaal

Sponsoring

Pygments

Pygments is a generic syntax highlighter written in Python

PSPSDK

Collection of tools and libraries written for Sony's Playstation Portable (PSP) gaming console

apt-setup

Part of Debian-Installer. Generate an /etc/apt/sources.list for the installed system

scim2-models

SCIM resources serialization and validation with Pydantic

scim2-client

Pythonically build SCIM requests and parse SCIM responses

scim2-tester

SCIM RFCs server compliance checker

scim2-cli

SCIM application development CLI

scim2-server

Lightweight SCIM2 server prototype

authlib

Identity and Access management library for python

synapse

Matrix homeserver written in Python/Twisted

pydanclick

*Add click options from a Pydantic model *

canaille

Lightweight identity and authorization management software

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant le printemps 2024

by Éloi Rivard <eloi@yaal.coop> from Yaal

Mécénat

Bat

Un clone de cat(1) avec coloration syntaxique et intégration Git

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

ihatemoney

Une application web simple de gestion de budget

python-libfaketime

Une alternative rapide à freezegun pour mocker les dates, en utilisant libfaketime

pytest-libfaketime

Prepare pytest à l’utilisation de python-libfaketime

pytest-iam

Serveur OAuth2/OIDC léger pour suites de tests unitaires

Debian

  • Extraction de la page de manuel de BlastEm car elle n'est plus dans le dépôt amont
  • Mise-à-jour de l'amélioration de la page de manuel de BlastEm sur la page de manuel nouvellement extraite

scim2-models

Sérialisation et validation de ressources SCIM avec Pydantic

scim2-client

Fabrication et analyse pythonique de requêtes SCIM

scim2-tester

Outil de vérification de conformité de serveurs aux normes SCIM

scim2-cli

SCIM application development CLI

Lire la suite…

Spring 2024 FOSS contributions from by the Yaal Coop team

by Éloi Rivard <eloi@yaal.coop> from Yaal

Sponsoring

Bat

A cat(1) clone with syntax highlighting and Git integration

canaille

Lightweight identity and authorization management software

ihatemoney

A simple shared budget manager web application

python-libfaketime

A fast time mocking alternative to freezegun that wraps libfaketime.

pytest-libfaketime

Prepare pytest for python-libfaketime

pytest-iam

A fully functional OAUTH2 / OpenID Connect (OIDC) server to be used in your testsuite

Debian

  • Extract BlastEm manpage because it does not existe anymore in the upstream repository
  • Update improved BlastEm manpage to the new manpage

scim2-models

SCIM resources serialization and validation with Pydantic

scim2-client

Pythonically build SCIM requests and parse SCIM responses

scim2-tester

SCIM RFCs server compliance checker

scim2-cli

SCIM application development CLI

Lire la suite…

Comment parler de politique

by Le blog de Dim' from Le blog de Dim'

Introduction #

L’heure est grave.

Dans 3 semaines, il y a une possibilité que l’extrême droite obtienne une majorité absolue à l’Assemblée Nationale.

Qu’est-ce que ça aura pour conséquences?

  1. Emmanuel Macron devra nommer un premier Ministre qui ne soit pas rejeté par une majorité à l’Assemblée - pas le choix, ça sera Jordan Bardella.

  2. On rentera dans une cohabitation, avec un Président qui a très peu de pouvoir, et un Premier Ministre qui gouverne, donc une politique d’extrême-droite pendant 3 ans (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).

  3. En 2027, Marine Le Pen remportera l’élection présidentielle et la France basculera vers le fascisme.

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.

Mes convictions #

Je suis convaincu de plusieurs choses:

  1. Le scénario décrit en introduction est crédible et peut nous amener au fascisme en France en 2027
  2. La meilleure stratégie pour éviter cela c’est de faire barrage au RN lors des législatives
  3. Le meilleur moyen de faire barrage au RN c’est de voter massivement pour les candidats et candidates Front Populaire dès le premier tour.
  4. 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.
  5. Vous qui me lisez, vous pouvez y faire quelque chose, et ce dès le premier tour.
  6. Le résultat du vote du 29 juin dépendra en grande partie des conversations que vous aurez autour de vous.

Le dernier point est important et je trouve qu’on en parle pas assez - et donc il mérite sa propre section.

De l’importance des conversations #

La question à se poser c’est : pourquoi est-ce que le Front Populaire ferait mieux en 2024 que la NUPES en 2022?

Notamment, qu’est-ce qui va pousser des personnes qui n’ont pas voté du tout ou ont voté autre chose que NUPES à voter Front Populaire?

Je pense que cela passera par une foule de gens (dont vous qui me lisez, j’espère) qui auront des conversations et arriveront à convaincre des indécis.

Pourquoi je pense que cela va marcher?

Je ne sais pas. Je n’ai pas de bon argument. C’est quelque chose que j’ai choisi de croire. Comme disait Chomsky:

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.

Traduction :

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.

Si vous avez tenu jusque là, on peut rentrer dans le vif du sujet.

Parler politique, mode d’emploi #

Quand je parle de conversation, je parle de deux personnes qui discutent ensemble - surtout pas d’un débat devant un public!

Assurez-vous que la personne avec qui vous discutez souhaite parler de politique (ça reste un tabou pour beaucoup de gens).

Si la personne vous dit “je compte m’abstenir”, “je compte voter blanc”, “je compte voter RN”, ne la jugez pas. Au contraire, écoutez-la et montrez-vous curieux. Exemple:

— Je ne peux pas voter pour le Front Populaire parce que Mélenchon et la LFI me font peur.

— Je comprends. Beaucoup de gens ont peur de la LFI. Qu’est-ce qui te fait peur chez LFI?

— Ce sont des extrémistes.

— Comment ça?

— Ils soutiennent les islamistes.

— Qu’est-ce que tu entends par islamistes?

— Ben, les terroristes du Hamas, tout ça. En plus ils sont antisémites.

Vous voyez l’idée - commencez par écouter et comprendre les émotions de la personne avec qui vous discutez avant de présenter votre point de vue.

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.

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.

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.

Autre exemple:

— Je vais pas voter parce que mon vote sert à rien

— Pourquoi tu penses que ton vote ne sert à rien?

— Parce qu’une fois élus ils font le contraire de ce qu’ils ont promis

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

Et là vous pouvez rentrer sur pourquoi la perspective de l’extrême droite au pouvoir vous touche vous, personnellement, ou bien vos proches.

Ainsi, vous allez vous montrer vulnérable et ce sera plus facile d’instaurer une confiance réciproque.

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.

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.

Conclusion #

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.

J’ai quelques idées sur la suite à donner, mais cela dépendra beaucoup de vos retours, chers lecteurs et lectrices.

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 ;)

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.

Lire la suite…

Chapitre 2023

by Brunélie Lauret <brunelie@yaal.coop> from Yaal

Une année de plus au compteur pour Yaal Coop !

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é : Yaal Coop recrute !

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.

Sans plus attendre, notre rapport de gestion :


Cher·e sociétaire,

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.


Les faits marquants et nos projets en 2023

Déménagement

En Septembre 2023, Yaal Coop a déménagé et s'est installé à Bègles, au 16 Rue des Terres Neuves !

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.

Actuellement et depuis l'ouverture du local, Yaal Coop en assure la gestion administrative et quotidienne, et recherche toujours de nouveaux locataires.

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.

Nos Projets

Portail RSE

https://portail-rse.beta.gouv.fr/

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.

Brunélie rejoint le projet en tant qu'UX/UI designer et à l'intégration à la fin de l'été.

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.

Lum1

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

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.

PodEduc

https://podeduc.apps.education.fr/

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.

B3Desk

https://github.com/numerique-gouv/b3desk

B3Desk est un projet de gestion des accès aux plateformes de visioconférences utilisées par l’éducation nationale.

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.

Telecoop

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.

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.

G4 Ingénierie

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.

Canaille

https://canaille.yaal.coop/

Canaille est notre logiciel libre de gestion d'identité et d'autorisations développé en interne.

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 article de blog a été publié pour retracer l'histoire du logiciel et préciser les développements réalisés avec l'aide de NLnet.

Nubla

https://nubla.fr/

Nubla est notre service d'e-mail, cloud et messagerie à destination des particuliers et professionnels.

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 !

GeoNature - citizen

https://enquetes.lashf.org/fr/home

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.

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 : https://undragon.org/

Yuticket

https://www.yuticket.com/

Yuticket est une billeterie en ligne dont Yaal Coop fait la maintenance. Le service évolue peu.

Supercoop

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.


Notre projet coopératif

Sociétariat

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.

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.

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 :

Collège des salariés - 50% des droits de vote

Prénom NOM / RAISON SOCIALE Nombre de parts
Brunélie LAURET 100
Camille DANIEL 100
Loan ROBERT 100
Stéphane BLONDON 100
Éloi RIVARD 100

Collège des investisseurs - 16,66% des droits de vote

Prénom NOM / RAISON SOCIALE Nombre de parts
GRUYERE 50 000

Collège des bénéficiaires - 16,66% des droits de vote

Prénom NOM / RAISON SOCIALE Nombre de parts
FINACOOP NOUVELLE-AQUITAINE 100

Collège des observateurs - 16,66% des droits de vote

Prénom NOM / RAISON SOCIALE Nombre de parts
Arthur LEDARD 100
Colin GARRIGA-SALAÜN 100

Favoriser une organisation horizontale

Présidence de Brunélie (actée à l'AG précédente)

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.

Évolutions dans notre gouvernance

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.

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.

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.

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.

Les rôles tournants définis actuellement sont les suivants :

  • 💌 Facteur·rice (qui relève le courrier entrant de nos différents boîtes mail et postale communes) - 2 semaines
  • 📟 Sentinelle (qui surveille les alertes levées par notre système de monitoring technique) - 2 semaines
  • ✒️ Secrétaire (qui programme et prend des notes de nos réunions régulières) - 3 mois
  • 🗨️ Facilitateur·rice (qui anime nos réunions régulières) - 3 mois
  • 🏦 Billetterie (qui fait la paie) - 3 mois
  • 🍲 Ticket-Restaurateur·rice (qui gère la distribution des tickets restaurants) - 3 mois
  • 📜 Marteau de la Justice (qui s'assure Yaal Coop respecte ses obligations légales) - 6 mois
  • 🕊️ Libre Entrepriseur·euse (qui représente Yaal Coop au sein du réseau Libre-entreprise) - 6 mois
  • 😽 Chaton·ne (qui représente Yaal Coop au sein du collectif CHATONS) - 1 an
  • 🪙 Argentier·e (qui suit et budgétise la trésorerie) - 1 an suivi de 1 an en backup
  • 🎊 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

Ils sont complétés par 4 rôles permanents occupés par tous les salariés :

  • 🚀 Responsable projet/prospect (qui est le référent d'un projet et le contact privilégié de ses éventuels clients)
  • 🛠️ Producteur·rice (qui produit du travail de qualité et se forme sur son métier)
  • 🎯 Chasseur·euse cueilleur·euse (qui s'occupe de la communication et du commerce)
  • 👤 Salarié·e (qui remplit ses obligations de salariés)

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.

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.

Favoriser l'activité et les acteurs ayant un impact social ou environnemental, de préférence locaux

Répartition du temps d'occupation

En 2023, le temps d'occupation de Yaal Coop a été réparti comme suit :

Activité Temps (pourcentage)
Prestation client 42%
Gestion de Yaal Coop 33%
Gestion de la SCI 13%
Investissement technique (Lum1) 6,6%
Investissement interne (Nubla, Canaille) 3%
Bénévolat 1,6%
Investissement subventionné (NLNet) 0,6%

Répartition du temps au cours de l'année 2023

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 :

Gestion de la SCI Gestion de Yaal Coop Investissement Prestation
15% ponctuellement (puis 10%) 25% 10% 50%

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

Économie Sociale et Solidaire (ESS)

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.

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€).

Impact environnemental

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

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.

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

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.

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 :

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

Réseaux

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.

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.

Yaal Coop est toujours adhérente du pôle de compétences régional en logiciels et technologies libres et open source NAOS.

Favoriser l'utilisation et le développement de logiciels libres

Projets et missions

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

Contributions de l'année à des logiciels libres

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

Participations

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.


Vie économique de la coopérative

Augmentation salariale

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.

Bilan financier et compte de résultat 2023

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.

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.

Le détail du bilan est disponible dans les comptes annuels 2023 rédigés par notre cabinet d'expertise comptable Finacoop.

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.

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.


Perspectives

Évolution des projets

Les principaux projets de l'équipe se poursuivent en 2024 :

  • 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.
  • 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.
  • 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.
  • 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.
  • 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 !

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.

Changements dans l’équipe

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

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.


Conclusion

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

Rédigé collectivement par l'équipe de Yaal Coop, Signé par Brunélie Lauret, Présidente de Yaal Coop

Lire la suite…

Python : Scanner un document sous Windows avec l'API WIA

by FLOZz from Human coders

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.


Commentaires
L'article Python : Scanner un document sous Windows avec l'API WIA a été posté dans la catégorie Python de Human Coders News

Lire la suite…

JavaScript hack update

by Olivier Pons from Olivier Pons

Mise à jour en pur JavaScript hacks

Voici une petite mise à jour en vanilla JS qui fait la même chose que ce que j’ai mis ici.

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);

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant l'hiver 2024

by Éloi Rivard <eloi@yaal.coop> from Yaal

Mécénat

PyPI search

Greffon Firefox pour chercher des bibliothèques Python hébergées par PyPI (pypi.org)

  • Remplacement des occurences de « Pypi » par « PyPI »
  • Publication d'une nouvelle version (1.0.1)

Bat

Un clone de cat(1) avec coloration syntaxique et intégration Git

HATop

Un client ncurses interactif pour HAProxy

Virt-Manager

Client lourd pour gérer des machines virtuelles

wtforms

Bibliothèque python de gestion de formulaires web

authlib

Bibliothèque python de gestion des identités et des accès

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

Matrix

Une nouvelle base de communication ouverte, intéropérable, décentralisée et en temps réel

Lire la suite…

Winter 2024 FOSS contributions from by the Yaal Coop team

by Éloi Rivard <eloi@yaal.coop> from Yaal

Sponsoring

PyPI search

Firefox plug-in to search Python libraries hosted at PyPI (pypi.org)

  • Replace Pypi occurrences by PyPI one
  • Release a new version (1.0.1)

Bat

A cat(1) clone with syntax highlighting and Git integration

HATop

An Interactive ncurses Client for HAProxy

Virt-Manager

Desktop user interface for managing virtual machines

wtforms

A flexible forms validation and rendering library for Python.

authlib

Identity and Access management library for python

canaille

Lightweight identity and authorization management software

Matrix

A new basis for open, interoperable, decentralised real-time communication

Lire la suite…

ssh : les nouveaux types de cryptographies et clés pour plus de sécurité

by Olivier Pons from Olivier Pons

GitHub et GitLab ont adopté des normes de sécurité SSH plus récentes et plus robustes pour renforcer la sécurité des connexions.

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.

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.

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, il faut donc impérativement changer la taille de la clé par au minimum 4096 :

ssh-keygen -t rsa -b 4096

Lire la suite…

Modification de la sortie de bat

by ascendances from ascendances

bat permet d’afficher le contenu d’un fichier en activant la coloration syntaxique par défaut. bat permet aussi de changer le thème (DarkNeon dans les captures d’écran suivant) ou les informations affichées.

Avec le code Python suivant contenu dans un fichier nommé futilite.py :

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]

L’ensemble des décorations possibles est affiché avec le paramètre full.

bat futilite.py --style="full"

Au contraire, la version sans décoration (et donc celle qui est le plus proche du comportement de cat) s’obtient avec le style plain. C’est aussi équivalent à l’utilisation de pygmentize avec un alias (cf. un article précédent).

bat futilite.py --style="plain"
Plusieurs blocs sont activables ou non en ajoutant des éléments au paramètre style. La liste des éléments est disponible dans la page de man. Par exemple, changes pour afficher des différences Git, header-filesize pour afficher la taille du fichier, rule pour afficher une ligne entre deux fichiers, etc.).

Par exemple, si on veut limiter l’affichage aux numéros de ligne, à la taille du fichier (et son contenu évidemment) :

bat futilite.py --style="numbers, header-size"

Personne n’ayant envie de retaper ce paramètre style en permanence, il est enregistrable dans le fichier $HOME/.config/bat/config (le chemin est modifiable par une variable d’environnement). Un contenu d’exemple est montré dans le README.md de bat.

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant l'automne 2023

by Éloi Rivard <eloi@yaal.coop> from Yaal

Mécénat

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

wtforms

Bibliothèque python de gestion de formulaires web

flask-wtf

Intégration de WTForms dans Flask

django-anymail

Anymail: Intégration de fournisseurs d'e-mails transactionnels dans Django

ihatemoney

Une application web simple de gestion de budget

authlib

Bibliothèque python de gestion des identités et des accès

flask-webtest

Utilitaires de test d'applications Flask avec WebTest

Lire la suite…

Autumn 2023 FOSS contributions from by the Yaal Coop team

by Éloi Rivard <eloi@yaal.coop> from Yaal

Sponsoring

canaille

Simplistic OpenID Connect provider over OpenLDAP

wtforms

A flexible forms validation and rendering library for Python.

flask-wtf

Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.

django-anymail

Anymail: Django email integration for transactional ESPs

ihatemoney

A simple shared budget manager web application

authlib

Identity and Access management library for python

flask-webtest

Lire la suite…

Canaille, un système léger de gestion d’identité et d’accès

by Éloi Rivard <eloi@yaal.coop> from Yaal

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.

Canaille

Au début étaient les annuaires

À 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 LDAP1 qui est utilisé pour cet usage, on parle alors d’annuaire.

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 (ou à oublier), on parle généralement d’inscription unique ou Single Sign On (SSO). 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.

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.

Mais LDAP, c’est aussi compliqué et austère. C’est une base de donnée en arbre 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évu2. Si on souhaite ensuite partager ces modèles de données, alors il est conseillé de s’enregistrer à l’IANA3, 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 ça fonctionne), et sans trop documenter leurs aventures. J’exagère à peine, si on compare4 le nombre de questions sur stackoverflow, pour ldap on en dénombre environ 1000 tandis que postgresql ou mongodb en comptent environ 14 000 et mysql 45 000.

Puis vint l’authentification unique

Lors de temps de bénévolat à Supercoop5, 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 gestion des membres, 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 ou Single Login Identification (SLI) 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.

Actuellement les protocoles de prédilection pour faire du SLI sont OAuth2 et OpenID Connect (OIDC)6. On note qu’il existe d’autres standards, plus historiques ou bien plus orientés vers les grosses organisations, tels SAML ou CAS. 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 groupe de travail oauth de l’IETF7. Mais là encore tout n’est pas rose et OIDC vient avec son lot de difficultés.

Tout d’abord, OAuth2 et OIDC c’est environ 30 standards complémentaires, 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 comprendre 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.8

Mais revenons à nos moutons. Pour Supercoop nous souhaitions trouver un outil qui soit d’une grande simplicité à plusieurs points de vue :

  • pour les utilisateur·ices : les coopérateur·ices du magasin. L’utilisation doit se faire sans aucune connaissance technique préalable, et sans assistance ;
  • pour l’équipe de gestion des membres 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.
  • enfin pour l’équipe informatique, 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. Et vues les descriptions que j’ai faites de LDAP et OIDC, vous commencez à cerner une partie du problème.

Notre recherche 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 ou Identity and Authorization Management (IAM) 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.

Canaille

Quelques temps après, notre prototype a grossi et a donné Canaille.

Les fonctionnalités

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.

Canaille peut être utilisé pour :

  • 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.
  • 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.
  • 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.
  • tester des applications utilisant OIDC. Nous utilisons aussi Canaille dans des suites de tests unitaires python, grâce à pytest-iam. 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.

Les choix techniques

Canaille est un logiciel écrit en python, avec flask pour le côté serveur et fomantic-ui et htmx 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.

Sous le capot, Canaille peut se brancher au choix à un annuaire LDAP ou à une base de données SQL.

Les techniques de développement

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 Nubla, 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.

Canaille suit le principe du développement dirigé par les tests, ou Test Driven Development (TDD), dans la mesure du possible. La couverture du code est de 100% (branches comprises), 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.

Canaille utilise tous les analyseurs et formatteurs de code source modernes, au sein de pre-commit, et les test unitaires sont joués sur toutes les versions de Python officiellement supportées.

Enfin la traduction de l’interface de Canaille se fait de manière communautaire sur weblate.

Contributions

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.

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.

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 RFC7591 et RFC9068 dans authlib, une brique utilisée pour la partie OIDC de Canaille.

Le résultat de ces efforts est visible dans nos articles trimestriels de contributions à des logiciels libres.

Le hasard des contributions nous a amené à partager la maintenance de certaines des bibliothèques que nous utilisons, comme wtforms qui permet de gérer les formulaires dans Canaille, ou encore nextcloud-oidc-login et OpenIDConnect-PHP qui permettent à nextcloud (le gestionnaire de fichiers proposé par Nubla) de se connecter à Canaille.

Nous sponsorisons aussi modestement tous les mois les mainteneur·ices de fomantic-ui et authlib.

L’aide de la fondation NLNet

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 NGI Zero Entrust de la fondation NLNet pour financer le support de travaux dans Canaille :

Canaille

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.

Et la suite ?

Passer en version bêta

Nous avons depuis le début gardé Canaille en version alpha, nous sommes à l’heure actuelle à la version 0.0.35. 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 remettant à plat la manière de configurer Canaille avant de passer Canaille en bêta, et lever les mises en garde d’usage.

Nous regroupons les tickets pour le passage en version bêta de Canaille dans ce jalon.

Passer en version stable

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.

Nous regroupons les tickets pour le passage en version stable de Canaille dans ce jalon.

Et au-delà…

Pour l’avenir nous souhaitons travailler sur le provisionnement, en implémentant la norme SCIM. 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.

Parmi les chantiers à venir, nous voyons aussi le travail sur la déconnexion unique, ou Single Log-Out (SLO). 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.

Enfin, nous aimerions travailler sur une gestion avancée des groupes d’utilisateur·ices et des droits, ainsi que sur des mécanismes d’authentification multi-facteurs.

Si tout cela vous intéresse, vous pouvez tester Canaille immédiatement sur notre interface de demo. Canaille est évidemment ouvert aux contributions, alors si vous souhaitez nous aider dans tout ça, la porte est ouverte !

  1. enfin, un logiciel qui implémente LDAP, ici je parle indifféremment du protocole ou de ses implémentations ↩︎
  2. du moins avec OpenLDAP ↩︎
  3. ce que nous avons fait, notre numéro à l’IANA est le 56207 ↩︎
  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 ↩︎
  5. le supermarché coopératif de l’agglomération bordelaise ↩︎
  6. par abus de langage, je dirai simplement OIDC ↩︎
  7. l’« Internet Engineering Task Force » un organsime étasunien de développement et de promulgation de standards ↩︎
  8. Ils peuvent aussi êtres moteurs de nouvelles améliorations, comme RFC7628 ou RFC9068 qui furent des usages avant d’être des standards. ↩︎

Lire la suite…

Canaille, a lightweight identity and authorization management software

by Éloi Rivard <eloi@yaal.coop> from Yaal

Since a while, the Yaal Coop team is working on Canaille, an identity and authorization management software (or IAM). 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.

Canaille

At first was the Single Sign On

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 (or to forget). This is what is called Single Sign On (SSO). 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.

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.

Its tree 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 schemas[/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 IANA[ref]what we did, our IANA number is 56207[/ref], and provide an online reference of your schemas.

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 just works. 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 stackoverflow, ldap has approximately 1000 questions, while postgresql or mongodb have around 14.000, and mysql has 45.000.

Then came the Single Log In

During our volunteer time at Supercoop[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 members management 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 Single Login Identification (SLI) 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.

Currently the predilection protocols for SLI are OAuth2 and OpenID Connect (OIDC)[ref]for sake of simplicity, I will keep to OIDC[/ref]. (There are other existing standards, more historical or more focused towards big organizations, like SAML or CAS.) The OAuth2 and OIDC specifications are recent 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 IETF oauth workgroup. But here again, everything is not perfect and OIDC comes with its difficulties. First of all, OAuth2 and OIDC make about 30 different standards, 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 RFC7628 or RFC9068 that were commonly used before they became standards.[/ref]

Let's get back on topic. For Supercoop, we wanted to find a tool that would be utterly simple from several point of views:

  • 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;
  • for the members management team. 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.
  • for the IT team. 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. And with the descriptions I made of LDAP and OIDC, you start to make an idea of the problem we have.

Our search 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.

Canaille

A few times later, our prototype had grown bigger and became Canaille.

The features

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.

Canaille can be used for:

  • 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.
  • 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.
  • 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.
  • test applications relying upon an OIDC server. We also use canaille in unit tests suites, with pytest-iam. This is a pytest plugin that configures and run a Canaille instance so your unit tests suite can achieve actual OIDC connections.

The technical choices

Canaille is written in Python, with Flask for the backend and fomantic-ui and htmx 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.

Under the hood, Canaille can be plugged to a LDAP directory or a SQL database.

The development techniques

We use Canaille in production, at Supercoop where it is used to manage 1800 users, but also in our own stack in our Nubla 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.

Cannaille development follows the principles of the Test Driven Development (TDD) when possible. The code coverage reaches 100% (including branches), 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.

Canaille uses all the modern Python source code linters and formatters, with pre-commit, and the unit tests are run on all the officially supported Python versions.

Finally, the translation of Canaille is done by the community with Weblate.

Contributions

Like most of modern software, Canaille relies on libraries so we don't have to re-invent what is already existing.

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.

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 RFC7591 and RFC9068 in authlib, a library Canaille uses to deal with OIDC.

The results of those efforts can be seen in our seasonal blogposts about our FLOSS contributions.

The chance of the contributions brought us to share the maintenance of certain libraries we rely upon, like wtforms that is a form management tool, or nextcloud-oidc-login and the underlying OpenIDConnect-PHP that allow nextcloud (the file manager integrated in Nubla) to connect with Canaille.

We also modestly sponsor the maintainers of fomantic-ui and authlib on a monthly basis.

The help of the NLNet foundation

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 NGI Zero Entrust fund of the NLNet foundation in the late 2022, for a amount of 7.000€, to help us realize tasks on Canaille (and around):

  • database connection genericity. This was a mandatory preparatory step to plugging additional databases than LDAP;
  • SQL databases support. This allows Canaille to connect to a lot of widespread databases like postgresql, mariadb and sqlite, thanks to sqlalchemy.
  • pytest-iam. This is a tool that can prepare and run a Canaille instance in the purpose of unit testing Python applications with pytest.

Canaille

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.

What's next?

Go in beta version

From the beginning we have kept Canaille in alpha, we are currently at version 0.0.35. 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 re-thinking the configuration files before we let Canaille go in bêta, and remove usage warnings.

We track the beta version tasks in this milestone.

Go in stable version

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.

We track the finale version tasks in this milestone.

And beyond…

In the future, we would like to work on provisioning, by implementing the SCIM 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.

Among the things we look forward to implement, there are also the Single Log-Out (SLO) 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.

At last, we would like to work on advanced group management and permissions, and on multi-factor authentication to bring even more flexibility and security in Canaille.

Canaille is open to contributions, if you want to help us in this endeavour, the door is open!

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant l'été 2023

by Éloi Rivard <eloi@yaal.coop> from Yaal

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.

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 base de données en mémoire nous a permis d'utiliser Canaille dans pytest-iam, un outil qui permet de lancer un serveur OpenID Connect dans des tests unitaires.

Mécénat

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

wtforms

Bibliothèque python de gestion de formulaires web

flask-wtf

Intégration de WTForms dans Flask

ihatemoney

Une application web simple de gestion de budget

python-slapd

Interface pythonique pour contrôler un serveur OpenLDAP

authlib

Bibliothèque python de gestion des identités et des accès

pytest-iam

Serveur OAuth2/OIDC léger pour vos tests unitaires

Debian

Lire la suite…

Summer 2023 FOSS contributions by the Yaal Coop team

by Éloi Rivard <eloi@yaal.coop> from Yaal

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.

We spent a bit of energy on Canaille, and implementing the big part of our NLNet subsidy, that is the database backend genericity. The inmemory backend allowed us to use canaille in pytest-iam, a tool that bring a lightweight OpenID Connect provider to be used in your unit tests.

Sponsoring

canaille

Simplistic OpenID Connect provider over OpenLDAP

wtforms

A flexible forms validation and rendering library for Python.

flask-wtf

Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.

ihatemoney

A simple shared budget manager web application

python-slapd

Controls a slapd process in a pythonic way

authlib

Identity and Access management library for python

pytest-iam

A lightweight OAuth2/OIDC server to be used in your test suite

Debian

Lire la suite…

Python : f-string vs str()

by Olivier Pons from Olivier Pons

Quelle est la différence de performance entre f"{x}" et str(x) ?

Voici mes tests qui m’ont surpris, car je m’attendais à l’inverse :

from typing import Dict

def benchmark() -> None:
  """Main
  function for benchmark.
  """
  t1 = timeit.timeit("f_str()",
                     globals=globals(),
                     number=50000000)
  t2 = timeit.timeit("u_str()",
                     globals=globals(),
                     number=50000000)
  t3 = timeit.timeit("n_str()",
                     globals=globals(),
                     number=50000000)
  d: Dict[str, float] = {
    "f-string": t1,
    "str": t2,
    "no str": t3
  }
  s: Dict[str, float] = {k: v
                         for k, v
                         in sorted(d.items(),
                                   key=lambda i:
                                   i[1])}
  f: float = min(s.values())
  print("Method\tTime\tPerc.")
  print("------\t----\t-----")
  for k, v in s.items():
    p: float = (v / f) * 100
    print(f"{k}\t{v:.2f}\t{p:.2f}%")

if __name__ == "__main__":
  import timeit
  class T:
    def __init__(
            self, l: str) -> None:
      self.l: str = l
  o: T = T("test")
  def f_str() -> str:
    return f"{o.l}"
  def u_str() -> str:
    return str(o.l)
  def n_str() -> str:
    return o.l
  benchmark()

Explications

  • f"{self.label}" 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 ;
  • str(self.label) appelle explicitement le constructeur de la classe str, ce est un peu plus lent en raison de l’appel de fonction.

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant le printemps 2023

by Éloi Rivard <eloi@yaal.coop> from Yaal

htmlRFC

Greffon Firefox affichant un lien des RFC au format texte brut vers une version au format HTML

Debian

Logrotate

Outil Unix pour administrer les journaux sur un système produisant de nombreux journaux

smtpdfix

Un serveur SMTP pour pytest avec encryption et authentification.

flask-themer

Support simple de thèmes dans les applications flask

zodburi

Construit des storage ZODB à partir d'URIs.

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

django-anymail

Intégration des e-mails dans Django pour les fournisseurs d'e-mails transactionels

simple-svelte-autocomplete

Composant svelte de suggestion d'éléments dans une liste déroulante

Lire la suite…

FOSS contributions from the Yaal Coop team during spring 2023

by Éloi Rivard <eloi@yaal.coop> from Yaal

htmlRFC

Firefox plug-in displaying a link for RFCs in plain text format to HTML one

Debian

Logrotate

Unix tool for administration of log files on a system which generates a lot of log files

smtpdfix

A SMTP server for use as a pytest fixture that implements encryption and authentication.

flask-themer

Simple theming support for Flask apps.

zodburi

Construct ZODB storage instances from URIs.

canaille

Simplistic OpenID Connect provider over OpenLDAP

django-anymail

Django email integration for transactional ESPs

simple-svelte-autocomplete

Simple Autocomplete / typeahead component for Svelte

Lire la suite…

Ruby Video : Plongez dans l'univers Ruby en vidéos !

by Camille Roux from Human coders

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.

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.


Commentaires
L'article Ruby Video : Plongez dans l'univers Ruby en vidéos ! a été posté dans la catégorie Python de Human Coders News

Lire la suite…

Chapitre 2022

by Camille Daniel <camille@yaal.coop> from Yaal

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 De Yaal à Yaal Coop qui raconte la genèse de Yaal Coop 🙈.

Pour remédier à ça, on a décidé de publier ici notre rapport de gestion 2022. 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 🙌.

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 faire un pas de côté, 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 🍻 !

Sans plus de transition, voici le rapport que nous leur avons adressé.

N'hésitez pas à passer nous voir pour en discuter plus largement si vous le souhaitez ! (Mais toujours pas le mercredi, c'est resté le jour du télétravail collectif 😉)


Cher·e sociétaire,

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.

Un peu d'histoire : les faits marquants de l'année 2022

  • janvier : Yaal Coop obtient l'agrément CII : 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 Telecoop, premier opérateur télécom coopératif, d'assistance et développement de nouveaux outils sur quelques jours par mois.
  • 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).
  • 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 Aquilenet 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 notre offre Nubla Pro !
  • 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.
  • 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. 🎉
  • juin : Une petite mission démarre avec Freexian pour retravailler son identité graphique et refondre ses deux sites web statiques ainsi que son fil d'actualités.
  • 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 !
  • 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 Projet Impact 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.
  • octobre : Une petite mission est réalisée pour PodEduc, une plateforme vidéo pour les agents de l'Éducation nationale, via deux contributions au logiciel libre Esup-Pod.
  • novembre : Notre projet interne Canaille, 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.
  • décembre : Nubla, 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.

Notre projet coopératif

Sociétariat

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.

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.

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.

La composition des collèges en date du 9 mai 2023 est la suivante :

  • Collège des salariés - 50% des droits de vote
Prénom NOM / RAISON SOCIALE    Nombre de parts
Brunélie LAURET 100
Camille DANIEL 100
Loan ROBERT 100
Stéphane BLONDON 100
Éloi RIVARD 100
  • Collège des investisseurs - 16,66% des droits de vote
Prénom NOM / RAISON SOCIALE    Nombre de parts
GRUYERE 50 000
  • Collège des bénéficiaires - 16,66% des droits de vote
Prénom NOM / RAISON SOCIALE    Nombre de parts
FINACOOP NOUVELLE-AQUITAINE 100
  • Collège des observateurs - 16,66% des droits de vote
Prénom NOM / RAISON SOCIALE    Nombre de parts
Arthur LEDARD 100
Colin GARRIGA-SALAÜN 100

(sous réserve de validation de l'entrée de Colin GARRIGA-SALAÜN par la prochaine Assemblée Générale)

Favoriser une organisation horizontale

Mise en place d'une forme d'holacratie dans Yaal Coop

Après quelques discussions et ateliers organisés en interne, nous avons décidé de nous inspirer de l'holacratie 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.

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.

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 💌 -qui relève le courrier entrant sur nos différentes boîtes aux lettres- ou Sentinelle 📟 -qui surveille et réagit aux alertes de monitoring-, à 2 ans avec backup pour le rôle d'Argentier·e 🪙 -qui met à jour et surveille la trésorerie-). 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.

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.

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.

Changement de présidence proposé en 2023

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 !

Favoriser l'activité et les acteurs ayant un impact social ou environnemental, de préférence locaux

Investissement technique

Nous sommes toujours associés avec Lum1, 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.

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.

Investissement interne

Notre projet Nubla, 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.

Économie Sociale et Solidaire (ESS)

Parmi nos clients, conformément à nos engagements en tant que SCIC, figurent des acteurs de l'économie solidaire et sociale comme Telecoop.

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.

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 Assistea, ainsi que Telecoop, notre fournisseur téléphonique mobile et notre client sur une mission du premier semestre 2022.

BetaGouv et direction du numérique pour l'éducation

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 Projet Impact développée par la direction générale des entreprises en lien avec BetaGouv, le frontal de visioconférence B3Desk et la plateforme de vidéos PodEduc portés par la direction du numérique pour l'éducation).

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.

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.

Acteurs locaux

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.

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.

Impact environnemental

Comme beaucoup, nous sommes sensibles aux enjeux environnementaux et tentons de limiter à notre échelle l'impact environnemental de la coopérative.

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 :

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

La séance de projection du documentaire libre "Responsables du Numérique" 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.

Réseau Libre Entreprise

Le réseau Libre-entreprise 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.

Favoriser l'utilisation et le développement de logiciels libres

L'ensemble de nos contributions à des logiciels libres sont visibles sur ces différents articles de blog, publiés de façon saisonnière :

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.

Pour appuyer cet attachement, nous avons adhéré en juillet 2022 à Nouvelle-Aquitaine Open Source (NAOS), 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.

Enfin en novembre 2022, nous avons contribué financièrement à hauteur de 500€ à l'AFPy (Association Francophone Python) 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.


Bilan financier et compte de résultat 2022

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.

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.

Le détail du bilan est disponible dans les comptes annuels 2022 rédigés par notre cabinet d'expertise comptable Finacoop.

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.

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.


Perspectives

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.

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 !

Le déménagement de Yaal Coop dans nos futurs locaux à Bègles est prévu pour l'été 2023 ! La gestion des travaux et la recherche de futurs colocataires se poursuivent.

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.


Conclusion

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

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.

Lire la suite…

Panda vs Numpy

by Olivier Pons from Olivier Pons

Ce qu’il faut retenir

Numpy et Pandas n’ont pas exactement les mêmes objectifs.

Dans la plupart des cas, NumPy peut être légèrement plus rapide que pandas, car NumPy est plus bas niveau et a moins de surcharge. 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. Les performances relatives de NumPy et pandas dépendent également des opérations spécifiques effectuées sur les données, 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 : read_csv, read_excel, groupby, pivot_table, merge, concat, melt, crosstab, cut, qcut, get_dummies et applymap.

Résultats

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.

Résultats pandas vs NumPy

Code source

Voici le code source que j’ai fait, qui appelle quelques fonctions connues de NumPy et de pandas.

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

Lire la suite…

Visite à la PyConFR 2023

by Stéphane Blondon <stephane@yaal.coop> from Yaal

La conférence PyConFR 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.

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 zou ainsi qu'avoir une Pull Request acceptée sur cpython (merci à Julien Pallard) et d'en faire une autre, suite à la précédente. :)

C'est aussi l'occasion de rencontrer et discuter dans les allées avec d'autres pythonistes.

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:

Django Admin comme framework pour développer des outils internes

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 :

  • la possibilité de modifier le nom 'Django admin' dans l'interface de connexion pour rassurer les utilisateurs
  • l'utilisation de 'create views' dans un script de migration permettant de faire des visualisations en lecture seule.

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.

Uncovering Python’s surprises: a deep dive into gotchas

Une présentation en anglais montrant des curiosités plus ou moins connues du langage. Une partie des exemples sont issus de wtfpython.

Faire du Python professionnel

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'article de blog intéressante néanmoins, avec des arguments contre les annotations de type.

Et un conseil pertinent : ne pas faire d'annotation sans mettre en place un outil (type mypy) dans la CI pour les vérifier. 😇

Portage Python sur Webassembly

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.

python -m asyncio -> pour avoir un shell python asynchone

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 pygame-web.github.io.

Fear the mutants. Love the mutants.

Comment être sûr que les tests vérifient bien ce qu'ils sont censés vérifier ? mutmut modifie le code source à tester et vérifie que les tests sont en erreur après la modification. La commande principale est mutmut run. Pour changer le comportement du code, mutmut accède et modifie l'AST (Abstact Syntax Tree) grâce à la bibliothèque parso.

Python moderne et fonctionnel pour des logiciels robustes

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.

Il a été question de typage avec les hints de Mypy mais aussi avec Pyright, 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.

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.

Le paramètre frozen du décorateur @dataclass(frozen=True) permet de rendre les instances immutables.

La classe typing.Protocol, décrite dans la PEP 544 et introduite dans Python 3.8 permet de définir des interfaces.

Une recommandation de vidéo : Functional architecture - The pits of success - Mark Seemann

Accessibilité numérique : faire sa part quand on est développeur·euse backend

Une introduction aux problématiques de l'accessibilité avec une démo percutante en vidéo 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.

Quelques petites choses glanées :

  • 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
  • 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
  • l'attribut html lang 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 🤯
  • 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...)
  • 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

Sensibiliser les producteurs d'une part significative des mediums d'information est toujours une bonne chose.

Interactive web pages with Django or Flask, without writing JavaScript

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

pyScript est un projet encore très jeune qui permet l'exécution de code Python dans le navigateur.

Merci à l'équipe de bénévoles pour l'organisation de la conférence. À l'année prochaine !

Lire la suite…

Contributions à des logiciels libres par l'équipe Yaal Coop durant l'hiver 2023

by Éloi Rivard <eloi@yaal.coop> from Yaal

Cet hiver nous avons surtout travaillé sur Canaille pour préparer l'implémentation de fonctionnalités sponsorisées par la fondation NLNet.

Documentation

Esup-Pod

Plateforme de partage vidéo pensée pour l'enseignement et la recherche

Contributions financées par la Direction du Numérique pour l'Éducation (pôle Formation Ouverte et A Distance)

DSFR

Système de design de l’État

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

nextcloud-oidc-login

Plugin OpenID Connect pour nextcloud

flask-shell-ptpython

Utilisation de l'interpréteur de commandes ptpython dans flask

authlib

Bibliothèque python de gestion des identités et des accès

wtforms

Bibliothèque python de gestion de formulaires web

flask-wtf

Intégration de WTForms dans Flask

python-caldav

Bibliothèque python pour le protocole CalDAV

aioimaplib

Bibliothèque python asyncio IMAP4rev1

simple-svelte-autocomplete

Composant svelte de suggestion d'éléments dans une liste déroulante

python-slapd

Interface pythonique pour contrôler un serveur OpenLDAP

supervisord

Un gestionnaire de processus écrit en Python

Lire la suite…

FOSS contributions from the Yaal Coop team during winter 2023

by Éloi Rivard <eloi@yaal.coop> from Yaal

This winter we have mainly worked on Canaille in order to prepare the implementation of features sponsored by the NLNet foundation.

Documentation

Esup-Pod

Video sharing website aimed at education and research

Contributions funded by the Direction du Numérique pour l'Éducation (Formation Ouverte et A Distance service)

DSFR

French State design system

canaille

Simplistic OpenID Connect provider over OpenLDAP

nextcloud-oidc-login

Nextcloud login via a single OpenID Connect 1.0 provider

flask-shell-ptpython

Ptpython shell for flask

authlib

Identity and Access management library for python

wtforms

A flexible forms validation and rendering library for Python.

flask-wtf

Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.

python-caldav

Python CalDAV library

aioimaplib

Python asyncio IMAP4rev1 client library

simple-svelte-autocomplete

Simple Autocomplete / typeahead component for Svelte

python-slapd

Controls a slapd process in a pythonic way

supervisord

A Process Control System written in Python

Lire la suite…

IUT alternants : projet Django / Python à rendre le 12 février minuit au plus tard

by Olivier Pons from Olivier Pons

A rendre le dimanche 12 février 2023 minuit au plus tard


Projet individuel


Comment le rendre

Faites un fichier README.txt et déposez-le ici
Dans le fichier README.txt, précisez :

  • le sujet choisi
  • l’adresse de votre site
  • un nom d’utilisateur
  • un mot de passe
  • (et plusieurs nom/mot de passe, s’il y a plusieurs niveaux de droits (administrateur/visiteur etc.))
  • si vous avez utilisé des librairies spécifiques que je vous ai autorisées, merci de le re-préciser

Sujet

Ce que vous voulez tant que c’est dans le cadre de ce que l’on a vu. Vous avez tout le Web comme inspiration !
N’oubliez pas de me donner le nom et le mot de passe pour se connecter !
Si vous gérez des profils différents (admin / user ou autre), donnez moi les noms et mots de passe de différents profils !


Fonctionnalités obligatoires

  • Nouveaux modèles
  • Nouvelles relations à mettre en oeuvre : ForeignKey, ManyToMany, OneToOne
  • Au moins un formulaire
  • Connexion + déconnexion (vu en cours)
  • Visualisation de tout dans l’interface d’administration

Sujets possibles

  1. Site de partage de photos
  2. Site de cocktails (cf ci-dessus)
  3. e-rated : site d’appréciations (selon des sujets, à définir)
  4. Ask-a-question : site où l’on pose des questions sur des sujets divers, et des gens répondent
  5. Write-a-book-together : site où l’on se connecte et où on peut écrire un livre à plusieurs
  6. Wedding-couple-site : site où l’on uploade + partage des photos de mariage + livre de commandes
  7. Playing-cards-collection : site où on scanne + échange des cartes (Magic the gathering)
  8. Polls-and-surveys : site de création de sondages (= QCM, exemple très beau ici : quipoquiz)
  9. Poems-generator : faire un cadavre exquis qui génère des poèmes + possibilité pour les utilisateurs de les noter / d’ajouter des mots
  10. 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
  11. 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)
  12. Le-bon-recoin : refaire le bon coin en plus simple
  13. 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
  14. Tv-fans : site de présentations + notes d’émissions télé
  15. 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.

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.

  1. Turn-by-turn : faire un jeu multijoueurs en tour par tour (jeu de cartes, de poker, ou de plateau etc)
  2. Chat-with-someone : site de chat/discussion
  3. A-maze-ing : site où l’on peut se ballader dans un labyrinthe et essayer d’en trouver la sortie

Sujet imposé si vous n’avez pas d’idée

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


Ce que vous devez rendre

Idéalement

Si vous n’avez pas le choix

Les fichiers source de votre projet


Pour favoriser votre organisation

Utilisez ce que l’on a vu en cours (Google boilerplate)


Librairies autorisées


React autorisé

Note pour ceux qui connaissent / font / du React : la librairie est autorisée, mais il me faut le code d’origine, et non pas le code minifié / de production.


Interdiction d’utiliser une librairie JavaScript qui ne vienne pas des sites autorisés précédemment


Retard

Après la date et heure limite

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).
Pour ceux qui essaient vraiment d’aller jusqu’à la dernière minute, toute heure entamée est comptée comme une heure complète.
Exemple : un point en moins si je le reçois un jour après à la minute près, soit date limite plus 00:01 minute.

N’oubliez pas de me donner le nom et le mot de passe pour se connecter !


Copier-coller

  • 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 ») :
    • si la personne est clairement nommée : note pour la fonctionnalité divisée par 2 (uniquement la moitié du travail a été faite) ;
    • 0 aux deux personnes sinon ;
  • 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 :
    • si vous ne savez pas m’expliquer le code alors 0 ;
    • 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.

Voici un exemple de ce que vous pouvez faire, si vous choisissez le projet cocktails.


PDFs

Python Django

Lire la suite…

Nombres décimaux et Python

by ascendances from ascendances

Python, comme de nombreux autres langages ainsi que des implémentations matérielles, suit la norme IEEE 754 pour manipuler les nombres à virgule (le type float 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.

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 :

$ python3 -q
>>> 1.9999999999999943e+71
1.9999999999999942e+71

ou un calcul qui devrait valoir 0 si les mathématiques étaient une science exacte :

$ python3 -q
>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17

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.

Pour éviter ces erreurs, il est possible d’utiliser la bibliothèque decimal incluse dans la bibliothèque standard :

$ python3 -q
>>> from decimal import Decimal
>>> decimal.Decimal('1.9999999999999943e+71')
Decimal('1.9999999999999943E+71')
>>> Decimal(1) / Decimal(10) + \
... Decimal(1) / Decimal(10) + \
... Decimal(1) / Decimal(10) - \
... Decimal(3) / Decimal(10)
Decimal('0.0')

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

Références

Lire la suite…

Dernières contributions à des logiciels libres par l'équipe Yaal Coop (automne 2022)

by Éloi Rivard <eloi@yaal.coop> from Yaal

pytest-httpserver

Serveur HTTP pour pytest

dnserver

Serveur DNS simpliste pour le développement

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

ZEO

Serveur de base de données pour ZODB

nextcloud-oidc-login

Plugin OpenID Connect pour nextcloud

authlib

Bibliothèque python de gestion des identités et des accès

aioimaplib

Bibliothèque python asyncio IMAP4rev1

MessagePack

Format de sérialisation binaire efficace (bibliothèque python)

simple-svelte-autocomplete

Composant svelte de suggestion d'éléments dans une liste déroulante

dnspython

outils DNS pour Python

Lire la suite…

Last FOSS contributions from the Yaal Coop team (automn 2022)

by Éloi Rivard <eloi@yaal.coop> from Yaal

pytest-httpserver

Http server for pytest to test http clients

dnserver

Simple development DNS server

canaille

Simplistic OpenID Connect provider over OpenLDAP

ZEO

ZODB Client-Server framework

nextcloud-oidc-login

Nextcloud login via a single OpenID Connect 1.0 provider

authlib

Identity and Access management library for python

aioimaplib

Python asyncio IMAP4rev1 client library

MessagePack

Efficient binary serialization format (python implementation)

simple-svelte-autocomplete

Simple Autocomplete / typeahead component for Svelte

dnspython

DNS toolkit for Python

Lire la suite…

Vérification de la syntaxe de certains fichiers de configuration

by ascendances from ascendances

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 :

1. Apache

Apache2 fournit apachectl. Si la syntaxe des sites actifs est correcte, la sortie sera :

# apachectl -t
Syntax OK

Avec un fichier de configuration incorrect nommé conte.conf contenant

<VirtualHost a.oree.du.bois:80>
    ServerName le.grand.mechant.loup.example
    CustomLog /il/etait/une/fois combined
    RencontreChaperonRouge on
</VirtualHost>

la sortie sera 

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

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 apachectl -t 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.

(test réalisé avec Apache/2.4.38)

2. OpenSSH

La commande sshd -t exécutée avec des droits root permet de vérifier la validité de la configuration du serveur openSSH (le fichier /etc/ssh/sshd_config sous Debian).
Si le fichier est correct, alors rien n’est affiché et la valeur de sortie est 0.
Avec un fichier sshd_config commençant par :

PetitPotDeBeurre on
Tartiflette off

La sortie sera :

# 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

avec une valeur de sortie de 255.

(test réalisé avec OpenSSH_7.9p1, OpenSSL 1.1.1d)

3. Sudo

Si une erreur est faite dans le fichier /etc/sudoers qui empêche sa relecture par l’exécutable sudo, il devient impossible d’utiliser la commande sudo. visudo permet d’éviter ce désagrément.
Supposons que l’utilisateur ait ajouté à la ligne 12,

Hello           MereGrand

puis enregistre le fichier :

% sudo visudo
/etc/sudoers:12:25: erreur de syntaxe
Hello           MereGrand
^
Et maintenant ?

Lorsque le fichier est incorrect, trois choix sont possibles :

  • remodifier le fichier
  • quitter sans enregistrer
  • quitter en enregistrant (une déception pourrait arriver peu de temps après)

L’éditeur par défaut utilisé par visudo est vi. Cela est modifiable en paramétrant des variables d’environnement comme $EDITOR. (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. man sudo si vous pensez que cette complexité a un intérêt dans votre cas.)

(testé avec visudo version 1.9.5p2, version de la grammaire de visudo : 48)

Faim de loup, fin d’article

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.

Lire la suite…

Dernières contributions à des logiciels libres par l'équipe Yaal Coop (été 2022)

by Éloi Rivard <eloi@yaal.coop> from Yaal

squeekboard

Un clavier virtuel pour Wayland

libcall-ui

Interface utilisateur pour les appels téléphoniques sous Linux

Mozilla Web Docs

Documentation sur les technologies du web, dont CSS, HTML et Javascript

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

Python

python-caldav

Debian Archive Kit (dak)

Programmes utilisés pour maintenir les archives du projet Debian

Python2 finira par disparaître

  • Suppression d'un contournement pour les version antérieures à 2.6 dans Webtest
  • Documentation : suppression d'un exemple basé sur python2 dans Honcho
  • Suppression de cas spécifiques à python2.7 dans setuptools
  • Suppression de python2 dans msgpack

tracker-miners

Collecteurs de données pour GNOME Tracker

poetry

Outil pour la gestion des dépendances et des paquets en Python

fhir-kindling

Brique de connexion à des serveurs de ressources FHIR

keyring_pass

Connecteur Password Store (pass) pour python-keyring

dnserver

Serveur DNS simpliste pour le développement

nextcloud-oidc-login

Plugin OpenID Connect pour nextcloud

Lire la suite…

Last FOSS contributions from the Yaal Coop team (summer 2022)

by Éloi Rivard <eloi@yaal.coop> from Yaal

squeekboard

An on-screen-keyboard input method for Wayland

libcall-ui

User interface for Linux phone calls

Mozilla Web Docs

Documentation about web technologies, including CSS, HTML, and JavaScript

canaille

Simplistic OpenID Connect provider over OpenLDAP

Python

python-caldav

Debian Archive Kit (dak)

Programs used to maintain the Debian project's archives

Python2 will disappear

  • Removal of a workaround for older releases than 2.6 in Webtest
  • Documentation: removal of an example based on python2 in Honcho
  • Removal of python2.7 specific cases in setuptools
  • Removal python2 support in msgpack

tracker-miners

Data collectors for GNOME tracker

poetry

Tool for dependency management and packaging in Python

fhir-kindling

FHIR resource and synthetic data set creation and management tool

keyring_pass

Password Store (pass) backend for python's keyring

dnserver

Simple development DNS server

nextcloud-oidc-login

Nextcloud login via a single OpenID Connect 1.0 provider

Lire la suite…

Revue logicielle du Librem 5 de Purism

by Éloi Rivard <eloi@yaal.coop> from Yaal

Après plusieurs années d'attente, nous venons de recevoir le Librem 5 que nous avions commandé chez Purism. C'est un téléphone orienté vie-privée dont les fonctionnalités notables sont :

  • l'utilisation de PureOS, une distribution GNU/Linux basée sur Debian, à la place d'Android ou iOS ;
  • l'interface graphique est GNOME avec quelques modifications ;
  • 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).

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.

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

Nous nous sommes concentrés sur les applications GNOME Core et Circle, ainsi que sur les applications mobiles développées par Purism.

Ce que nous attendons d'un téléphone est qu'il nous permette de :

  • passer des appels
  • recevoir et envoyer des SMS
  • recevoir et envoyer des emails
  • être utilisé comme réveil
  • gérer ses contacts
  • gérer des listes de tâches
  • être utilisé comme un appareil de géolocalisation
  • naviguer sur internet
  • jouer de la musique
  • prendre des photos
  • prendre des notes
  • afficher des documents
  • partager sa connexion internet
  • être utilisé comme lampe-torche
  • discuter avec des gens

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.

Nous avons testé le téléphone sous PureOS byzantium, et mis à jour les applications grâce à Flatpak quand c'était possible afin de bénéficier des avancées de GNOME 42.

Bloquants

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.

Confort

Dans cette catégorie nous lisons ce qui améliorerait notre confort. Cela concerne principalement les interfaces.

Paillettes

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.

Lire la suite…

Purism Librem 5 software review : our list to Santa

by Éloi Rivard <eloi@yaal.coop> from Yaal

After several years of waiting, we just received our Librem 5 phone from Purism. The Librem 5 phone is a privacy-oriented phone which notable features are:

  • it uses PureOS, a GNU/Linux distribution based on Debian, instead of Android or iOS;
  • the interface is based on GNOME with a few modifications;
  • it has kill switches to physically disable wifi, bluetooth, cellular data, camera and microphone.

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.

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 GNOME Core and Circle apps, and mobile/Librem5 specific apps developed by Purism. What we expect from a phone is to:

  • place calls
  • receive and send SMS
  • receive and send emails
  • be used as an alarm clock
  • manage contacts
  • manage tasks
  • be used as a geolocation navigation device
  • browse the internet
  • play music
  • take photos
  • take notes
  • display documents
  • share internet connection
  • be used as a torchlight
  • discuss with people

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.

We have tested the phone running PureOS byzantium, and we updated all the apps through Flatpak when possible so we could get the latest GNOME 42 fixes.

Blockers

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.

Comfort

In this category we put the issues that would improve our comfort. This mainly concern mobile UX improvements.

Sparkles

In this category we put everything else that we met during our test, from nice-to-have features to slight mobile UX improvements:

Lire la suite…

Dernières contributions à des logiciels libres par l'équipe Yaal Coop (début 2022)

by Éloi Rivard <eloi@yaal.coop> from Yaal

Ces derniers mois nous avons principalement contribué à canaille, le serveur d'identité que nous développons, ainsi que le menu d'autocomplétion simple-svelte-autocomplete et le greffon nextcloud-oidc-login qui permet à nextcloud de se connecter à des serveurs d'identité.

wtforms

Bibliothèque python de gestion de formulaires web

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

webtest

Bibliothèque de tests unitaires pour applications web

nextcloud

Logiciel de partage et de synchronisation de fichiers

nextcloud-oidc-login

Plugin OpenID Connect pour nextcloud

ansible

Outil d'automatisation des déploiements

simple-svelte-autocomplete

Composant svelte de suggestion d'éléments dans une liste déroulante

fhir-kindling

Brique de connexion à des serveurs de ressources FHIR

Debian

Lire la suite…

Last FOSS contributions from the Yaal Coop team (winter 2022)

by Éloi Rivard <eloi@yaal.coop> from Yaal

Those last months we mainly worked on canaille, our identity server, as well as the autocompletion menu simple-svelte-autocomplete and nextcloud-oidc-login that allows nextcloud to connect to identity servers.

wtforms

A flexible forms validation and rendering library for Python.

canaille

Simplistic OpenID Connect provider over OpenLDAP

webtest

Wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.

nextcloud

Nextcloud server, a safe home for all your data

nextcloud-oidc-login

Nextcloud login via a single OpenID Connect 1.0 provider

ansible

simple IT automation platform

simple-svelte-autocomplete

Simple Autocomplete / typeahead component for Svelte

fhir-kindling

FHIR resource and synthetic data set creation and management tool

Debian

Lire la suite…

Visite aux JDLL 2022

by Stéphane Blondon <stephane@yaal.coop> from Yaal

Les 2 et 3 avril 2022, plusieurs associé·es de Yaal Coop étaient présents aux 23ièmes Journées du Logiciel Libre 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.

Comme nous construisons un service d'hébergement nommé nubla, assister aux présentations sur le collectif des CHATONS (Collectif des Hébergeurs Alternatifs, Transparents, Ouverts, Neutres et Solidaires) et sur zourit 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 !

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 transformer Yaal en SCIC 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 : Hashbang, Tadaa et Probesys.

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 bépo. 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 - ergoL -, ont piqué notre curiosité.

Tellement de type de claviers dans la zone des associations !

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 DebConf et PyconFr).

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.

Du coup, encore merci à tous les organisateurs et présentatrices, et vivement la prochaine ?

Lire la suite…

Supprimer les plus vieux fichiers d’un dossier tant qu’on dépasse une certaine taille

by Olivier Pons from Olivier Pons


Exemples de lancement du script

Notez qu’il faut lancer en utilisant « source« 

  • Supprimer les plus vieux fichiers du dossier courant (./) tant qu’il prend plus de 96Mo :
    source ./clean_custom.sh --path ./ -l 9600000
  • Supprimer les plus vieux fichiers du dossier temporaire (/tmp/) tant qu’il prend plus de 2Go :
    source ./clean_custom.sh --path /tmp/ -l 2000000000

Code du script

#!/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 > 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 > 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" ] && echo "Path empty" && usage && 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

Lire la suite…

Retour d'expérience concernant l'usage d'AlpineLinux comme conteneur

by Stéphane Blondon <stephane@yaal.coop> from Yaal

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 site web, il est clairement indiqué « Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox. ». Voyons quelles contraintes cela apporte :

Les performances de musl

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.

À l'exécution, musl est plus lente que la glibc. Par exemple, une compilation de cpython est deux fois plus lente 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. Mimalloc semble être une bonne piste à l'avenir, mais pour l'instant, il faut vivre avec ce niveau de performance.

L'environnement espace utilisateur

busybox

AlpineLinux utilise busybox pour les outils Unix de base. Busybox est un projet éprouvé et utilisé depuis de nombreuses années dans l'embarqué.

Ce choix permet de minimiser la taille des outils embarqués par Alpine.

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.

systemd

AlpineLinux utilise les scripts de démarrage classique Unix (dans /etc/init.d/) et non systemd. Selon les besoins et préférences de chacun, cela peut être une qualité ou un défaut.

Les mises-à-jour

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

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.

Conclusion

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.

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.

Lire la suite…

Hello Debian en Brainfuck

by ascendances from ascendances

screenshots.debian.net 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 beef affichant un classique
Hello Word!. Mais on peut aussi personnaliser en affichant un
Hello Debian! :

Utilisation de beef

Brainfuck

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, wikipedia 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.
Voici une version commentée du programme utilisé (le début est quasi-identique au hello world fourni sur la page wikipedia puisqu’on veut écrire la même chose) :

++++++++++          affecte 10 à la case 0
[                   boucle initialisant des valeurs au tableau 
   >                avance à la case 1 
   +++++++          affecte 7 à la case 1
   >                avance à la case 2
   ++++++++++       affecte 10 à la case 2 
   >                avance à la case 3
   +++              affecte 3 à la case 3
   >                avance à la case 4
   +                affecte 1 à la case 4
   >                avance à la case 5
   +++++++++++      affecte 11 à la case 5
   <<<<<            retourne à la case 0
   -                enlève 1 à la case 0
]                   jusqu'à ce que la case 0 soit = à 0

La boucle initialise le tableau en 10 itérations et son état est alors :

Case 0 1 2 3 4 5
Valeur 0 70 100 30 10 110

Suite du programme :

>++                 ajoute 2 à la case 1 (70 plus 2 = 72)
.                   imprime le caractère 'H' (72)
>+                  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)
>++                 ajoute 2 à la case 3 (30 plus 2 = 32)
.                   imprime le caractère ' '(espace) (32)

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

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

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

screenshots.debian.net

Une capture de l’exécution du programme est disponible pour les interpréteurs beef et hsbrainfuck sur screenshot.debian.net.
Les images disponibles sur screenshots.debian.net sont aussi réutilisées par le service packages.debian.org (par exemple packages.debian.org) et par certains gestionnaires de paquets.
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).

Lire la suite…

Django scripting : « AppRegistryNotReady: Apps aren’t loaded yet » solution

by Olivier Pons from Olivier Pons

Si vous voulez faire un script simple qui veut importer votre application construite sur le framework Django, vous ferez sûrement ce code :

import django
from app.models import MyModel

Vous aurez sûrement cette erreur : django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

Pas de panique !
La solution est de lancer setup() de votre application avant les imports, comme suit :

import django

if __name__ == '__main__':
    django.setup()
    # import AFTER setup
    from app.models import MyModel
    # je peux maintenant utiliser MyModel!!

Lire la suite…

Dernières contributions à des logiciels libres par l'équipe Yaal Coop (fin 2021)

by Éloi Rivard <eloi@yaal.coop> from Yaal

yii2-authclient

Brique de connexion OpenID Connect, notamment utilisée par humhub

rcmcarddav

Greffon de synchronisation des contacts CardDAV pour l'interface web de gestion des mails Roundcube

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

wtforms

Bibliothèque python de gestion de formulaires web

flask-wtf

Intégration de WTForms dans Flask

secure-cookie

La bibliothèque secure-cookie devrait être utilisée dans Flask à l'avenir.

aports

Paquets de la distribution Alpine Linux

sheraf

Surcouche objet à ZODB

OpenID-Connect-PHP

Bibliothèque OpenID Connect en PHP

nextcloud-oidc-login

Plugin OpenID Connect pour nextcloud

python-slapd

Interface pythonique pour contrôler un serveur OpenLDAP

Pygments

Bibliothèque Python de coloration syntaxique

Debian

Lire la suite…

Last FOSS contributions from the Yaal Coop team (fall 2021)

by Éloi Rivard <eloi@yaal.coop> from Yaal

yii2-authclient

Yii 2 authclient extension

rcmcarddav

CardDAV plugin for RoundCube Webmailer

canaille

Simplistic OpenID Connect provider over OpenLDAP

wtforms

A flexible forms validation and rendering library for Python.

flask-wtf

Simple integration of Flask and WTForms, including CSRF, file upload and Recaptcha integration.

secure-cookie

Secure cookies and sessions for WSGI

aports

Alpine packages build scripts

sheraf

A versatile ZODB abstraction layer

OpenID-Connect-PHP

Minimalist OpenID Connect client

nextcloud-oidc-login

Nextcloud login via a single OpenID Connect 1.0 provider

python-slapd

Controls a slapd process in a pythonic way

Pygments

Pygments is a generic syntax highlighter written in Python

Debian

Lire la suite…

Un disque chiffré et partitionné avec Ubuntu

by Loan Robert <loan@yaal.coop> from Yaal

Ça y est, c'est décidé, vous avez une nouvelle machine, ou bien vous voulez repartir sur des bases propres et vous aimeriez chiffrer votre disque pour protéger vos données.

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... Partitionner est une très bonne idée.

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.

Pas de panique, vous êtes au bon endroit, cet article va vous donner les étapes à suivre pour installer Ubuntu 21.04 (mais également beaucoup de versions précédentes et probablement beaucoup de futures versions) en ayant des partitions, notamment votre /home, sur un disque chiffré.

Backup de vos données

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.

Bref, il faut sauvegarder vos fichiers personnels, vos identités, vos configurations particulières, noter vos applications préférées...

Fichiers

Rien de très surprenant ici, votre dossier /home est probablement un bon endroit pour commencer.

Faites un backup de tout ce que vous voulez garder quelque part, comme un ssd, une clé usb, ou sur un Nextcloud de chez Nubla ☁️ par exemple, un super service de cloud hébergé par une petite coopérative Bordelaise sympathique.

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.

Applications

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

Paquets apt

Vous pouvez utiliser cette commande :

comm -23 <(apt-mark showmanual | sort -u) <(gzip -dc /var/log/installer/initial-status.gz | sed -n 's/^Package: //p' | sort -u) > apps_backup.txt

pour générer une liste des paquets qui ont été manuellement installés et les enregistrer sur un fichier apps_backup.txt. 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.

apt-mark showmanual 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 /var/log/installer/initial-status.gz. 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 apps_backup.txt.

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.

snap

Il est possible que dans certains cas vous ayez eu besoin de snap pour installer certains logiciels. vous pouvez les lister avec :

snap list

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.

Ubuntu Software

Vous pouvez aussi lancer Ubuntu Software Center et afficher la liste des applications installées.

Fichiers de configuration

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.

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 :

  • les fichiers .profile ou .bash_profile ou .bash_login... pour les sessions
  • .bashrc, .zshrc et/ou autres pour le shell
  • les aliases
  • .gitconfig et/ou .hgrc pour la config de vos VCS
  • la config de votre prompt
  • .vimrc pour la config de vim
  • ...

Identités

À 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é...

Installation d'Ubuntu

Vous êtes détendu, frais, tout est en sécurité, alors vous êtes prêt.

Lancer Ubuntu

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

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 "F12", 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 "Enter" jusqu'à ce qu'un son soit émis...).

Une fois qu'Ubuntu a été lancé depuis la clé, l'installeur se lance automatiquement. Vous pouvez cliquer sur "Try Ubuntu" ou bien aller un peu en avant dans l'installation de votre Ubuntu ce qui pourra peut-être vous faciliter la suite.

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

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.

Partitionner le disque

Nous allons utiliser fdisk depuis le terminal avec "ctrl-alt-t" (ou bien "super-a" et rechercher le terminal).

Pour simplifier le processus et comme la plupart des commandes nécessitent un niveau de permission superuser, il faut entrer :

sudo -s

Ensuite, vous pouvez lister les disques disponibles avec :

fdisk -l

Le disque en question sera probablement /dev/sda ou /dev/vda pour moi c'était plutôt /dev/nvme0n1. La suite de cette doc suivra les particularités de ma machine.

Pour partitionner ce disque, entrez :

fdisk /dev/nvme0n1

Il nous faut une partition EFI, une partition de boot, et une autre partition (celle qui sera chiffrée) qui occupera le reste du disque. Dans fdisk, pour obtenir de l'aide, appuyez sur "m" et en cas de doute sur les différentes partitions, vous pouvez appuyer sur "q" pour quitter sans sauvegarder vos modifications.

EFI

Pour créer la première partition EFI, appuyez sur

n

Le prompt va alors vous demander le numéro de la partition, gardez la valeur par défaut en pressant

Ensuite, il vous demande quel est le premier secteur à allouer. Par défaut, ce sera le premier qu'il trouve, appuyez donc sur

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

+2G

Boot

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 :

n
↵
↵
+2G

À chiffrer

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 :

n
↵
↵
↵

Il faut maintenant sauvegarder toutes ces modifications de la table de partition en pressant

w

Les partitions sont maintenant créées, nous pouvons passer au chiffrement de cette dernière partition nommée nvme0n1p3.

Chiffrer votre partition principale

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 déchiffrer le disque. Ici, pour l'exemple, nous l'appellerons pasvraimentcrypté.

Nous pouvons lancer la procédure de chiffrement avec

cryptsetup luksFormat /dev/nvme0n1p3

Le prompt demandera confirmation en entrant YES ce que nous pouvons faire en toute sérénité. Il demandera ensuite d'entrer la passphrase, ce sera votre clé pour déchiffrer votre disque à chaque démarrage, ne l'oubliez pas !

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

cryptsetup luksOpen /dev/nvme0n1p3 pasvraimentcrypté

Comme nous ouvrons un volume chiffré, le prompt nous demande la passphrase. Cette commande va créer un nouveau device nommé /dev/mapper/pasvraimentcrypté.

Nous allons ensuite utiliser LVM2 (Logical Volume Manager) pour partitionner ce nouveau device. Dans notre cas, nous voulons une partition root de minimum 8G pour l'OS, une partition home pour l'utilisateur et une partition swap 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.

Nous allons faire de notre partition déchiffrée un volume physique :

pvcreate /dev/mapper/pasvraimentcrypté

Puis créer un groupe ubuntu (ou autre) :

vgcreate ubuntu /dev/mapper/pasvraimentcrypté

Et enfin les volumes logiques du groupe ubuntu :

lvcreate -L 64G -n root ubuntu
lvcreate -L 8G -n swap ubuntu
lvcreate -l 100%FREE -n home ubuntu

Nous pouvons maintenant relancer l'installeur. Lorsque celui-ci demandera de choisir le type d'installation, cliquez sur le bouton "Autre chose", ce qui nous permettra d'utiliser les partitions et volumes créés. Configurons les trois volumes logiques :

  • /dev/mapper/ubuntu-root

    • Utiliser comme : Ext4 journaling filesystem
    • Formater la partition
    • Point de montage : /
  • /dev/mapper/ubuntu-swap

    • Utiliser comme : Swap area
  • /dev/mapper/ubuntu-home

    • Utiliser comme : Ext4 journaling filesystem
    • Formater la partition
    • Point de montage : /home

Et pour les devices :

  • /dev/nvme0n1p1

    • Utiliser comme : EFI
  • /dev/nvme0n1p2

    • Utiliser comme : Ext2 filesystem
    • Formater la partition
    • Point de montage : /boot

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.

Instructions de déchiffrement au démarrage

Ubuntu est installé sur votre machine. Il nous faut maintenant décrire quel device doit être déchiffré au démarrage et comment. 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.

Mais avant tout, il nous faut copier l'UUID du disque chiffré. Ouvrez un nouveau terminal (ou un nouvel onglet) et entrez

sudo blkid /dev/nvme0n1p3

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 "shift+ctrl+c" pour copier le texte en surbrillance et "shift+ctrl+v" pour le coller.

Basculer sur la nouvelle installation

Nous allons utiliser chroot pour passer dans le nouveau système. Entrez les commandes suivantes :

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

Nous sommes maintenant dans le nouveau système, avec différents devices montés sur différents répertoires.

Instructions de démarrage

Nous devons créer le fichier /etc/crypttab. 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 😘

pasvraimentcrypté   UUID=e7167ac4-b606-4be0-98a7-ace4e5e13f6b   none    luks,discard

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.

Sauvegardez ce fichier et quittez l'éditeur (pas le terminal).

Mettre à jour initramfs

Une fois l'éditeur quitté, toujours dans le terminal, il nous suffit de rentrer la commande suivante :

update-initramfs -k all -u

Nous pouvons maintenant quitter chroot en tapant

exit

Depuis notre shell de départ, il nous faut maintenant démonter mnt avec

umount -R /mnt

Fin

Nous pouvons maintenant fermer le shell et relancer la machine. Au démarrage, elle devrait nous demander la passphrase pour déchiffrer le device pasvraimentcrypté puis Ubuntu se lancera normalement.

La commande :

lsblk

nous permet d'avoir un visuel sur le résultat de nos différentes manipulations :

NAME                      MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
nvme0n1                   259:0    0 476,9G  0 disk
├─nvme0n1p1               259:1    0     2G  0 part  /boot/efi
├─nvme0n1p2               259:2    0     2G  0 part  /boot
└─nvme0n1p3               259:3    0 472,9G  0 part
  └─pasvraimentcrypté     253:0    0 472,9G  0 crypt
    ├─ubuntu-root         253:1    0    64G  0 lvm   /
    ├─ubuntu-swap         253:2    0     8G  0 lvm   [SWAP]
    └─ubuntu-home         253:3    0 400,9G  0 lvm   /home

On peut résumer cela ainsi :

  • le disque physique nvme0n1 est divisé en trois partitions physiques : nvme0n1p1, nvme0n1p2 et nvme0n1p3
  • la partition nvme0n1p1 est une partition EFI (nécessaire depuis Ubuntu 20.04) requise par le système d'exploitation
  • la partition nvme0n1p2 est la partie /boot qui permet au système de démarrer
  • la partition nvme0n1p3 contient un volume chiffré pasvraimentcrypté
  • ce volume chiffré pasvraimentcrypté que l'on doit déchiffrer au démarrage contient les trois volumes logiques LVM suivants :
  • ubuntu-root, la racine de l'arborescence du système Ubuntu
  • ubuntu-swap, l'extension de mémoire vive
  • ubuntu-home, contenant les dossiers et fichiers personnels des utilisateurs, isolé du reste du système

Ça y est, votre nouvelle vie commence avec votre nouvelle machine super secrète super rangée ! 🥳

Lire la suite…

Premier pied dans Yaal, en sabots

by Brunélie Lauret <brunelie@yaal.coop> from Yaal

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 !

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.

Ma première mission ? Développer l'identité visuelle du projet tout neuf de quelques associé⋅es de Yaal : Une brasserie !

La Brasserie du Sabot, c'est quoi ?

Le projet d'associé⋅es de Yaal. Une brasserie artisanale installée à Villenave d'Ornon, au sud de Bordeaux.

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 !

Pour moi, en tant que graphiste, ça fait deux grands axes à explorer pour concilier tout le monde :

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

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

Des idées en vrac

Dessins de départ pour la brasserie

Inspirations de dessin à la ligne claire, mais aussi de découpage de pochoir, puis de gravure.

et ça sur des bouteilles, ça donnerait quoi ?

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 :

Pistes et essais d'étiquettes

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.

Mockups d'étiquettes sur des bouteilles

Le choix final

Avec ces prévisualisations en tête, plus simple de se faire une idée et de savoir ce qui nous parle vraiment.

Voilà le logo choisi, qui servira aussi pour les étiquettes d'expérimentation :

Logo final de la Brasserie du Sabot

Déclinaison

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.

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.

Etiquettes finales (en situation ?) Etiquettes finales (en situation ?) Les étiquettes finales, après retouches faites en interne à la brasserie.

Le site

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.

Puis dans un second temps est venue la partie boutique, celle qui permet de commander ses bières en ligne !

Homepage du site de la brasserie

Page boutique de la brasserie

Tada !

Et surtout, n'hésitez pas à aller jeter un oeil par vous même sur 🍺 https://sabot.beer 🍺 !

Lire la suite…

De Yaal à Yaal Coop

by Camille Daniel <camille@yaal.coop> from Yaal

Yaal Coop 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 Yaal SAS, créée il y a bien plus longtemps, en 2010 (ce qui ne rajeunit pas ses fondateurs Arthur et Colin !).

Comme je sais que la co-existence des deux entreprises peut être source de confusion, voici ma tentative pour raconter l'aventure Yaal Coop.

Disclaimer : mon point de vue est personnel et forcément biaisé. Et pas forcément très synthétique non plus. 😗🎶

Yaal kézako ?

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.

Auto-organisation et auto-gouvernance 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.

Une autre particularité de Yaal est son modèle économique reposant sur l'investissement technique. 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.

Car cela marche : le plus gros projet de Yaal, Myelefant, est revendu 21 millions d'euros en novembre 2019 !

Pourquoi créer Yaal Coop ?

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.

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é. 😅

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.

Alors que certain·es profitent de ce tournant pour se lancer dans une aventure de production de bière, 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é. 💪

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 coopérative, 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).

Qu'est-ce qui change alors dans Yaal Coop ?

Yaal Coop est une Société Coopérative d'Intéret Collectif (SCIC). Entre autre, ça veut dire que :

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

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

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

Aujourd'hui à Yaal Coop nous avons désigné 4 collèges :

  • celui des salarié·es 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

  • celui des bénéficiaires (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

  • celui des investisseur·euses qui nous a permis d'accueillir Yaal SAS et de bénéficier d'un premier apport pour lancer l'activité !

  • et celui des observateur·rices et soutiens, 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.

Pour créer Yaal Coop, nous nous sommes fait accompagner par Finacoop Nouvelle Aquitaine, 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.

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

Mais concrètement au quotidien ça fonctionne comment ?

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 à 5 coopérateur·rices salarié·es associé·es, 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 😩).

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.

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. (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é !).

Lorsque tout le monde est arrivé, on commence notre weekly 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é.

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.

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 (sans risquer d'oublier la dernière étape de bien fêter la fête 🎉) ?).

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.

De manière plus macro, on a fait le choix du salaire unique et du temps plein 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.

On a eu pas mal de discussions riches sur le sujet, en particulier une session animée par David Bruant, 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 Scopyleft par exemple, où chacun se paie ce dont il a besoin après avoir pris soin d'en discuter avec tout le monde.

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

Côté projets, on continue l'investissement technique (comme avec notre premier projet Lum1 !), mais on fait aussi un peu de bénévolat à Supercoop (le supermarché coopératif de Bordeaux) et d'autres projets internes : bientôt Nubla ☁️ ?! 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.

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 participer à des projets qui ont du sens et avec des personnes qui partagent nos valeurs.

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.

Yaal Coop n'a même pas un an, on n'est qu'au début de l'aventure et de l'expérimentation ! 🌱

Et Yaal SAS alors ?

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 9 associé.es 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 ! 🍻

*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 ?)

Lire la suite…

Python 3.10 : récapitulatif des nouveautés

by Olivier Pons from Olivier Pons

Pep 604

Tester plusieurs types avec le | :

isinstance(5, int | str)
isinstance(None, int | None)
isinstance(42, None | int)
issubclass(bool, int | float)

Même chose pour les annotations :

def ma_fonction(
        ma_liste: List[int | str],
        param: int | None
    ) -> float | str:
    pass

Messages d’erreur plus parlants

  • 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
  • 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

Le match/case

Le match/case de Python est similaire à l’instruction switch/case, qui est reconnue comme un « pattern matching structurel » en Python.

Le match/case de Python se compose de trois entités principales :

  1. Le mot-clé match
  2. Une ou plusieurs clauses case
  3. Du code pour chaque case

Là où Python se démarque des autres langages, c’est que l’on peut faire un match sur des patterns !

Exemples de match, du plus simple au plus avancé :


Match très simple, avec le « or »

exemple = True
match exemple:
    case (True|False):
        print("C'est un booléen")
    case _ :
        print("Ce n'est pas un booléen")


Récupérer les sous-patterns

def alarm(item):
    match item:
        case [time, action]:
            print(f"{time} ! C'est l'heure de {action}!")
        case [time, *actions]:
            print(f'{time} !')
            for action in actions:
                print(f"C'est l'heure {action}!")
alarm(['Bon après-midi', 'de travailler'])
alarm(['Bonjour', 'du petit déjeuner', 'se laver les dents'])


Nommer les sous-patterns

def alarme(item):
    match item:
        case [('bonjour' | 'bonsoir') as time, action]:
            print(f"{time.title()} ! Il faudrait {action} !")
        case _:
            print('Mot-clé invalide.')
alarme(['bonsoir', 'travailler'])
alarme(['bonjour', 'petit déjeuner', 'se laver les dents'])


Nommer les sous-patterns et filtres conditionnels

def alarme(item):
    match item:
        case ['bonsoir', action] if action not in ['travailler']:
            print(f'Journée finie ! Il faut {action}!')
        case ['bonsoir', _]:
            print('Il faut se reposer !')
        case [time, *action]:
            print(f'{time.title()}! Il faut {" et ".join(action)}.')
        case _:
            print('Mot-clé invalide.')
alarme(['bonsoir', 'travailler'])
alarme(['bonsoir', 'jouer'])
alarme(['bonjour', 'petit déjeuner', 'se laver les dents'])


Match sur des objets

class Move:
    def __init__(self, horizontal=None, vertical=None):
        self.horizontal = horizontal
        self.vertical = vertical
def str_move(move):
    match move:
        case Move(horizontal='est', vertical='nord'):
            print('Dir. nord-est')
        case Move(horizontal='est', vertical='sud'):
            print('Dir. sud-est')
        case Move(horizontal='ouest', vertical='nord'):
            print('Dir. nord-ouest')
        case Move(horizontal='ouest', vertical='sud'):
            print('Dir. sud ouest')
        case Move(horizontal=None):
            print(f'Dir. {move.vertical}')
        case Move(vertical=None):
            print(f'Dir. {move.horizontal}')
        case _:
            print('? Move inconnu ?')
d1 = Move('est', 'sud')
d2 = Move(vertical='nord')
d3 = Move('centre', 'centre')
str_move(d1)
str_move(d2)
str_move(d3)

Lire la suite…

Design et création d'un nuage, Nubla.io

by Brunélie Lauret <brunelie@yaal.coop> from Yaal

C'est quoi, Nubla ?

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.

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.

Bannière nubla.io

☁️


Design et création d'un nuage, Nubla.io ☁️

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.

La seconde, c'est de créer quelque chose qui me fasse plaisir à imaginer, à dessiner, puis à intégrer.

Utiliser des outils et des techniques qui me plaisent : coolors pour le choix des palettes de couleur, me tourner vers des polices d'écriture libres, des illustrations open source aussi avec undraw, l'utilisation de CSS Grid pour l'intégration...

Premières pistes

Palettes, tests de fonts avec le texte nubla.io

Quand j'ai proposé au vote les différentes palettes à l'équipe, on s'en est sortis avec une égalité retentissante.

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.

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.

Les fonts testées ici sont :

  • Jost - Une police d'écriture libre, adaptée à la technologie variable font d'OpenType, reproduisant l'esprit de la légendaire Futura.
  • Varela Round - Une police d'écriture ronde, sympathique, créée par le designer Joe Prince.

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

Tests d'interaction des couleurs entre elles

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.

Image du blob de fond

Wireframes

Sur la sturcture du site, j'avais très envie de travailler avec CSS Grid 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.

Wireframe de la page d'accueil, en noir et blanc

Wireframe de la page à propos, en noir et blanc

Déclinaison de maquettes

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.

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.

Maquettes graphiques du site Nubla.io

Maquettes graphiques du site Nubla.io

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.

☁️


Le Site

Structure du site :

Schéma de la structure du site

  • Le body, sur lequel je place le blob de fond.
  • 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
  • Un layout en grille CSS de 5 colonnes, séparées par des gouttières de 20px.
  • 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.

Les petits détails qui font plaiz

... ou comment faire l'effet de soulignement dynamique des liens :

Gifs de quelques interactions animées, genre le soulignage des liens

C'est fait comme ça :

.line {
    display: inline-block;
    position: relative;
    font-style: normal;
    z-index: 1;
    color:var(--dark);
}

a.line:hover, a.line:focus {
    color:var(--dark);
}
.line::after {
    width: 100%;
    height: .7em;
    content:" ";
    background-color: var(--yellow);
    position: absolute;
    left:10px;
    bottom:0px;
    z-index: -2;
}
a.line::before {
    width: 0%;
    height: .7em;
    content:" ";
    background-color: var(--magenta);
    position: absolute;
    left:10px;
    bottom:0px;
    z-index: -1;
    transition: .2s all;
}
a.line:hover::before, a.line:focus::before {
    width: 100%;
    transition: .2s all;
}

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.

☁️


Et voilà !

Vous voulez voir ce que ça donne en vrai ? C'est par là : 👉 https://nubla.io 👈

Et n'hésitez pas à faire un tour sur notre sondage concernant vos usages e-mail, cloud et internet, et savoir si l'offre de Nubla pourrait vous intéresser !

J'espère que la lecture vous a plu !

Lire la suite…

Dernières contributions à des logiciels libres par l'équipe Yaal Coop (rentrée 2021)

by Éloi Rivard <eloi@yaal.coop> from Yaal

pytest

Outil de tests unitaires en Python

simple-svelte-autocomplete

Composant svelte de suggestion d'éléments dans une liste déroulante

toast-ui editor

Éditeur markdown wysiwyg en Javascript

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

sheraf

Surcouche objet à ZODB

ZEO

Serveur de base de données pour ZODB

rstr

Bibliothèque Python produisant des chaînes de caractères aléatoire

Pygments

Bibliothèque Python de coloration syntaxique

  • Ajout d'un lexeur à Pygments pour le format Procfile. 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).

Python.org

  • Correction d'un exemple de code sur le site python.org. La correction est intégrée dans le dépôt, mais pas encore disponible sur le site.

Lire la suite…

Last FOSS contributions from the Yaal Coop team (summer 2021)

by Éloi Rivard <eloi@yaal.coop> from Yaal

pytest

The pytest framework makes it easy to write small tests, yet scales to support complex functional testing

simple-svelte-autocomplete

Simple Autocomplete / typeahead component for Svelte

toast-ui editor

Markdown WYSIWYG Editor

canaille

Simplistic OpenID Connect provider over OpenLDAP

sheraf

A versatile ZODB abstraction layer

ZEO

ZODB Client-Server framework

rstr

rstr is a helper module for easily generating random strings of various types.

Pygments

Pygments is a generic syntax highlighter written in Python

Python.org

Lire la suite…

Manifeste agile et confinement - une rétrospective

by Le blog de Dim' from Le blog de Dim'

Introduction - retour sur le manifeste agile #

Relisons-le ensemble, il est là:

=> https://agilemanifesto.org/iso/fr/manifesto.html

Manifeste pour le développement Agile de logiciels

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 :

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

Nous reconnaissons la valeur des seconds éléments, mais privilégions les premiers.

Notez que la comparaison “les individus et les interactions plus que processus et les outils” est en premier.

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

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.

Explorons ensemble ce paradoxe, en se replongeant dans l’effet du confinement en entreprise.

Ce qu’était le confinement #

Le confinement au niveau des individus #

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 :

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 …)

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 …)

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)

Sans oublier les personnes qui pratiquaient le télétravail depuis déjà longtemps, ou celles qui ont simplement changé d’emploi

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.

Le confinement au niveau des interactions entre individus #

D’un autre côté, les conditions matérielles des interactions entre individus ont radicalement changé.

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

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 :

  • de part à et d’autre d’un bureau pour un conversation “officielle”
  • entre deux portes - par exemple juste avant ou juste après une réunion
  • autour de la machine à café pour parler de la météo
  • autour d’un verre dans un bar en fin d’après-midi pour décompresser après le boulot
  • à la table d’un restaurant le midi pour une réunion commerciale
  • etc.

Voici une liste exhaustive des différentes façons dont une conversation peut avoir lieu si les deux personnes ne sont /pas/ face à face :

  • voix seulement (téléphone)
  • texte seulement (SMS ou messagerie instantanée)
  • vidéo-conférence (audio et vidéo - avec messagerie instantanée incluse ou non)

Et c’est à peu près tout ce que la technique permet aujourd’hui - qu’on le veuille ou non !

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 ?

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 …

L’impact du confinement sur une entreprise fonctionnant sans le Principe d’Humanité #

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 !

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 déjà un processus.

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.

Au final, les problèmes liés véritablement au confinement vont être perçus comme des problèmes “d’organisation du travail”.

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.

À 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” …

L’impact du confinement sur une organisation fonctionnant suivant le Principe d’Humanité #

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 déjà traiter.

Et en tout cas, une entreprise suivant le Principe d’Humanité aura de bien meilleures chances de gérer correctement la fin du confinement.

Conclusion et retour sur l’agilité en entreprise #

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.

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.

J’espère vous avoir convaincu maintenant que le dernier principe agile (réagir au changement) découle en fait du premier.

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

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.

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 …

Lire la suite…

Dernières contributions à des logiciels libres par l'équipe Yaal Coop

by Éloi Rivard <eloi@yaal.coop> from Yaal

simple-svelte-autocomplete

Composant svelte de suggestion d'éléments dans une liste déroulante

canaille

Serveur OpenID Connect simpliste, basé sur OpenLDAP

sheraf

Surcouche objet à ZODB

python-slapd

Bibliothèque python pour contrôler un server OpenLDAP

  • Création et publication du projet.

cpython

wtforms

Bibliothèque python de gestion de formulaires web

Debian

Lire la suite…

Last FOSS contributions from the Yaal Coop team (spring 2021)

by Éloi Rivard <eloi@yaal.coop> from Yaal

simple-svelte-autocomplete

Simple Autocomplete / typeahead component for Svelte

canaille

Simplistic OpenID Connect provider over OpenLDAP

sheraf

A versatile ZODB abstraction layer

python-slapd

Controls a slapd process in a pythonic way

  • Project creation and publication.

cpython

wtforms

A flexible forms validation and rendering library for Python.

Debian

Lire la suite…

Python : compiler et faire tourner plusieurs versions sans collisions

by Olivier Pons from Olivier Pons

Il faut aller chercher le code source qui vous intéresse.

Exemple, faire tourner un « vieux » Python 3.6, aller dans les versions ici et prendre celle qui nous intéresse.

Puis récupérer le code source et le compiler :

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 && make
sudo make altinstall

Et voilà :

~/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.
>>>

Lire la suite…

Une page se tourne

by Le blog de Dim' from Le blog de Dim'

Une page se tourne … #

Vendredi dernier j’ai signé une rupture conventionnelle qui mettra fin au contrat qui me lie à Tanker le 24 février 2021.

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!

Et ensuite ? #

Plusieurs possibilités s’ouvrent à moi.

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.

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.

Parmi les sujets sur lesquels je me sens prêt à donner des cours dès maintenant:

  • Le langage de programmation Python (Voir: https://dmerej.info/python/)
  • Les bonnes pratiques de développement (tests automatiques, intégration continue, DevOps, revue de code, …)
  • Les méthodes agiles (SCRUM et Lean en particulier)
  • etc …

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.

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.

Une invitation #

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.

Comme d’habitude, ma page de contact est là si vous avez des pistes à me suggérer, des questions à me poser, ou pour toute autre remarque.

À bientôt !

Lire la suite…

Écriture de tests en Python: pytest et TDD

by Le blog de Dim' from Le blog de Dim'

Note : cet article reprend en grande partie le cours donné à l’École du Logiciel Libre 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 cleancoders.com 1

Assertions #

En guise d’introduction, penchons-nous un peu sur le mot-clé assert.

def faire_le_café(au_régime=False, sucre=True):
     if au_régime:
         assert not sucre

Que se passe-t-il lorsque ce code tourne avec au_régime à True et sucre à True ?

>>> faire_le_café(au_régime=True, sucre=True)
Traceback (most recent call last):
  File "foo.py", line 7, in <module>
    faire_le_café()
  File "foo.py", line 5, in faire_le_café
    assert not sucre
AssertionError

On constate que assert a évalué la condition et comme celle-ci était “falsy”, il a levé une exception nommée AssertionError

On peut modifier le message de l’assertion en rajoutant une chaîne de caractères après la virgule :

def faire_le_café(au_régime=False, sucre=True):
     if au_régime:
         assert not sucre, "tu es au régime: pas de sucre dans le café!"

Et on peut aussi vérifier que assert ne fait rien si la condition est “truthy” :

>>> x = 42
>>> assert x
# rien

À quoi servent les assertions #

Comme on l’a vu, utiliser assert ressemble fortement à lever une exception. Dans les deux cas, on veut signaler à celui qui appelle notre code que quelque chose ne va pas. Mais assert est différent par deux aspects :

  • Il peut arrive que la ligne contenant assert soit tout simplement ignorée 2.
  • assert et souvent utilisé pour signaler qu’il y a une erreur dans le code qui a appelé la fonction, et non à cause d’une erreur “extérieure”

Voir cet article de Sam & Max pour plus de détails.

Qu’est-ce qu’un test ? #

Voici un exemple minimal :

# dans calc.py
def add_one(x):
     return x + 2
# dans test_calc.py
import calc

result = calc.add_one(3)
assert result == 4, "result != 4"

On retrouve l’idée d’utiliser assert pour indiquer une erreur interne au code. En l’occurrence, si on lance le script test_calc.py, on va obtenir :

$ python3 test_calc.py
Traceback (most recent call last):
  File "test_calc.py", line 4, in <module>
    assert result == 4, "result != 4"
AssertionError: result != 4

Notez que le message d’erreur ne nous indique pas la valeur effective de result, juste sa valeur attendue.

Quoi qu’il en soit, le code dans test_calc.py nous a permis de trouver un bug dans la fonction add_one de calc.py

Code de test et code de production #

On dit que calc.py est le code de production, et test_calc.py le code de test. Comme son nom l’indique, le code de production sert de base à un produit - un programme, un site web, etc.

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 auteurs du code.

Les deux valeurs du code #

Une petite digression s’impose ici. Selon Robert C. Martin, le code possède une valeur primaire et une valeur secondaire.

  • La valeur primaire est le comportement du code - ce que j’ai appelé le produit ci-dessus
  • La valeur secondaire est le fait que le code (et donc le produit) peut être modifié.

Selon lui, la valeur secondaire (en dépit de son nom) est la plus importante : dans software, il y a “soft”, par opposition à hardware. 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.

Ainsi, si le code de test n’a a priori pas d’effet sur la valeur primaire du code (après tout, l’utilisateur du produit n’est en général même pas conscient de son existence), il a un effet très important sur la valeur secondaire, comme on le verra par la suite.

pytest #

On a vu plus haut comment écrire du code de test “à la main” avec assert. Étoffons un peu l’exemple :

# dans calc.py

def add_one(x):
     return x + 2

def add_two(x):
     return x + 2
# dans test_calc.py

result = calc.add_one(3)
assert result == 4

result = calc.add_two(5)
assert result == 7

On constate que tester le code ainsi est fastidieux :

  • Les valeurs effectives ne sont pas affichées par défaut
  • Le programme de test va s’arrêter à la première erreur, donc si calc_one est cassé, on ne saura rien sur l’état de calc_two
  • On ne peut pas facilement isoler les tests à lancer

C’est là que pytest entre en jeu.

On commence par créer un virtualenv pour calc et par installer pytest dedans 3

$ mkdir -p venvs && cd venvs
$ python3 -m venv calc
$ source calc/bin/activate
(calc) $ pip install pytest

Ensuite, on transforme chaque assertion en une fonction commençant par test_ :

import calc

def test_add_one():
    result = calc.add_one(3)
    assert result == 4, "result != 4"


def test_add_two():
    result = calc.add_two(5)
    assert result == 7

… et on corrige les bugs :

def add_one(x):
     return x + 1


def add_two(x):
    return x + 2

Enfin, on lance pytest en précisant le chemin de fichier de test :

$ pytest test_calc.py
============================= test session starts ==============================
test_calc.py ..                                                          [100%]
========================== 2 passed in 0.01 seconds ===========================

Chaque point après test_calc.py représente un test qui passe. Voyons ce qui arrive si on ré-introduit un bug :

def add_one(x):
     return x + 3


def add_two(x):
    return x + 2
$ 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)
>       assert result == 4
E       assert 6 == 4

test_calc.py:5: AssertionError

À noter :

  • Le test pour add_two a quand même été lancé
  • La valeur effective est affiché sous la ligne d’assert
  • La backtrace a été affiché
  • On a une vue du code qui a produit le bug
  • Le test qui a échoué est affiché avec un F majuscule

On peut aussi dire à pytest de ne lancer que les tests qui ont échoués à la session précédente :

$ pytest test_calc.py --last-failed
run-last-failure: rerun previous 1 failure

test_calc.py
=================================== FAILURES ===================================
_________________________________ test_add_one _________________________________

Cool, non ?

Limites des tests #

Avant de poursuivre, penchons-nous sur deux limitations importantes des tests.

Premièrement, les tests peuvent échouer même si le code de production est correct :

def test_add_one():
   result = add_one(2)
   assert result == 4

Ici on a un faux négatif. L’exemple peut vous faire sourire, mais c’est un problème plus fréquent que ce que l’on croit.

Ensuite, les tests peuvent passer en dépit de bugs dans le code. Par exemple, si on oublie une assertion :

def add_two(x):
    return x + 3

def test_add_two():
    result = calc.add_two(3)
    # fin du test

Ici, on a juste vérifié qu’appeler add_two(3) ne provoque pas d’erreur. On dit qu’on a un faux positif, ou un bug silencieux.

Autre exemple :

def fonction_complexe():
   if condition_a:
       ...
   if condition_b:
      ...

Ici, même s’il n’y a que deux lignes commençant par if, 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.

Dans le même ordre d’idée, les tests ne pourront jamais vérifier le comportement entier du code. On peut tester add_one() avec des exemples, mais on voit difficilement commeent tester add_one() avec tous les entiers possibles. 4

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.

Empêcher les régressions #

On a vu comment les tests peuvent mettre en évidence des bugs présents dans le code.

Ainsi, à tout moment, on peut lancer la suite de tests pour vérifier (une partie) du comportement du code, notamment après toute modification du code de production.

On a donc une chance de trouver des bugs bien avant que les utilisateurs du produit l’aient entre les mains.

Refactorer sans peur #

Le deuxième effet bénéfique est lié au premier.

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.

Une des solutions est de commencer par effectuer un refactoring, c’est-à dire de commencer par adapter le code mais sans changer son comportement (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é.

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.

Une discipline #

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 difficile à maîtriser. Cela demande un état d’esprit différent 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.

Ce que je vous propose ici c’est une discipline : 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.

Commençons par les règles :

  • Règle 1 : Il est interdit d’écrire du code de production, sauf si c’est pour faire passer un test qui a échoué.
  • 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)
  • 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é
  • 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. 5

Et voici une procédure pour appliquer ces règles: suivre le cycle de dévelopement suivant :

  • Écrire un test qui échoue - étape “red”
  • Faire passer le test - étape “green”
  • Refactorer à la fois le code de production et le code de test - étape “refactor”
  • Retour à l’étape “red”.

TDD en pratique #

Si tout cela peut vous semble abstrait, je vous propose une démonstration.

Pour cela, on va utiliser les règles du bowling.

Comme on code en anglais6, on va utiliser les termes anglophones. Voici les règles :

  • Un jeu de bowling comporte 10 carreaux (ou frames).
  • Chaque frame comporte deux lancers (ou roll) et 10 quilles (ou pins)
  • Si on renverse toutes les quilles en un lancer, on marque un abat (ou strike)
  • Si on renverse toutes les quilles dans un même carreau, on marque une réserve (ou spare)

On calcule le score frame par frame :

  • Si on fait un strike, on marque 10 points, plus les points obtenus à la frame suivante (donc 2 rolls)
  • Si on fait une spare, on marque 10 points, plus les points obtenus au lancer suivant (donc juste le roll suivant)
  • Sinon on marque le total de quilles renversées dans la frame

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.

Un peu d’architecture #

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.

On peut se dire que pour calculer le score, une bonne façon sera d’avoir une classe Game avec deux méthodes:

  • roll(), qui sera appelée à chaque lancer avec le nombre de quilles renversées en paramètre
  • score(), qui renverra le score final

Au niveau du découpage en classes, on peut partir du diagramme suivant:

class diagram

On a:

  • Une classe Game qui contient des frames
  • Chaque frame est une instance de la class Frame
  • Chaque frame contient une ou deux instances de la class Roll
  • Une classe Roll contenant un attribut pins correspondant au nombre de quilles renversées.
  • Une classe TenthFrame, qui hérite de la classe Frame et implémente les règles spécifiques au dernier lancer.

C’est parti #

Retours aux règles:

  • Règle 1: Il est interdit d’écrire du code de production, sauf si c’est pour faire passer un test qui a échoué.
  • 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)
  • 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é
  • 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. 5

Comme pour l’instant on a aucun code, la seule chose qu’on puisse faire c’est écrire un test qui échoue.

⁂ RED⁂

On crée un virtualenv pour notre code:

$ python3 -m venvs/bowling
$ source venvs/bowling/bin/activate
$ pip install pytest

On créé un fichier test_bowling.py qui contient juste une ligne:

import bowling

On lance les tests:

$ pytest test_bowling.py
test_bowling.py:1: in <module>
    import bowling
E   ModuleNotFoundError: No module named 'bowling'

On a une erreur, donc on arrête d’écrire du code de test (règle 2), et on passe à l’état suivant.

⁂ GREEN⁂

Pour faire passer le test, il suffit de créer un fichier bowling.py vide.

$ pytest test_bowling.py
collected 0 items

========================= no tests ran in 0.34 seconds ========================

Bon, clairement ici il n’y a rien à refactorer (règle 4), donc on repart au début du cycle.

⁂ RED⁂

Ici on cherche à faire échouer le test le plus simplement possible.

Commençons simplement par vérifier qu’on peut instancier la class Game :

import bowling

def test_can_create_game():
    game = bowling.Game()
$ pytest test_bowling.py
>       game = bowling.Game()
E       AttributeError: module 'bowling' has no attribute 'Game'

Le test échoue, faisons-le passer :

⁂GREEN⁂
class Game:
    pass

Toujours rien à refactorer …

⁂RED⁂

Écrivons un test pour roll() :

def test_can_roll():
    game = bowling.Game()
    game.roll(0)
$ pytest test_bowling.py
>       game.roll(0)
E       AttributeError: 'Game' object has no attribute 'roll'
⁂GREEN⁂

Faisons passer les tests en rajoutant une méthode :

class Game:
    def roll(self, pins):
        pass

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 …

⁂RED⁂

On continue à tester les méthodes de la classe Game, de la façon la plus simple possible :

def test_can_score():
    game = bowling.Game()
    game.roll(0)
    score = game.score()
$ pytest test_bowling.py
>       game.roll(0)
E       AttributeError: 'Game' object has no attribute 'roll'
⁂GREEN⁂

On fait passer le test, toujours de la façon la plus simple possible :

class Game:
    def roll(self, pins):
        pass

    def score(self):
    	pass
⁂ REFACTOR⁂

Le code production a l’air impossible à refactorer, mais jetons un œil aux tests :

import bowling

def test_can_create_game():
    game = bowling.Game()


def test_can_roll():
    game = bowling.Game()
    game.roll(0)


def test_can_score():
    game = bowling.Game()
    game.roll(0)
    game.score()

Hum. Le premier et le deuxième test sont inclus exactement dans le dernier test. Ils ne servent donc à rien, et peuvent être supprimés.

⁂RED⁂

En y réfléchissant, can_score() ne vérifie même pas la valeur de retour de score(). Écrivons un test légèrement différent :

def test_score_is_zero_after_gutter():
    game = bowling.Game()
    game.roll(0)
    score = game.score()
    assert score == 0

gutter signifie “gouttière” en anglais et désigne un lancer qui finit dans la rigole (et donc ne renverse aucune quille)

$ pytest test_bowling.py
>       assert score == 0
E       assert None == 0
⁂GREEN⁂

Faisons le passer :

class Game:
    def roll(self, pins):
        pass

    def score(self):
        return 0

Notez qu’on a fait passer le test en écrivant du code que l’on sait être incorrect. Mais la règle 3 nous interdit d’aller plus loin.

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 spécifié l’API de la classe Game. Le test, bien qu’il ne fasse que quelques lignes, nous indique l’existence des métode roll() et score(), les paramètres qu’elles attendent et, à un certain point, la façon dont elles intéragissent

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 pendant que vous l’implémentez. Et, en vous forçant à ne pas écrire trop de code de production, vous avez la possibilité de vous concentrer uniquement sur l’API de votre code, sans vous soucier de l’implémentation.

Bon, on a enlevé plein de tests, du coup il n’y a encore plus grand-chose à refactorer, passons au prochain.

⁂RED⁂

Rappelez-vous, on vient de dire que le code de score() est incorrect. La question devient donc : quel test pouvons-nous écrire pour nous forcer à écrire un code un peu plus correct ?

Une possible idée est d’écrire un test pour un jeu où tous les lancers renversent exactement une quille :

def test_all_ones():
    game = bowling.Game()
    for roll in range(20):
        game.roll(1)
    score = game.score()
    assert score == 20
>       assert score == 20
E       assert 0 == 20
⁂GREEN⁂

Ici la boucle dans le test nous force à changer l’état de la class Game à chaque appel à roll(), ce que nous pouvons faire en rajoutant un attribut qui compte le nombre de quilles renversées.

class Game:
    def __init__(self):
        self.knocked_pins = 0

    def roll(self, pins):
        self.knocked_pins += pins

    def score(self):
        return self.knocked_pins

Les deux tests passent, mission accomplie.

⁂REFACTOR⁂

Encore une fois, concentrons-nous sur les tests.

def test_score_is_zero_after_gutter():
    game = bowling.Game()
    game.roll(0)
    score = game.score()
    assert score == 0


def test_all_ones():
    game = bowling.Game()
    for roll in range(20):
        game.roll(1)
    score = game.score()
    assert score == 20

Les deux tests sont subtilement différents. Dans un cas, on appelle roll() une fois, suivi immédiatement d’un appel à score().

Dans l’autre, on appelle roll() 20 fois, et on appelle score() à la fin.

Ceci nous montre une ambiguïté dans les spécifications. Veut-on pouvoir obtenir le score en temps réel, ou voulons-nous simplement appeler score à la fin de la partie ?

On retrouve ce lien intéressant entre tests et API : aurions-nous découvert cette ambiguïté sans avoir écrit aucun test ?

Ici, on va décider que score() n’est appelé qu’à la fin de la partie, et donc réécrire les tests ainsi , en appelant 20 fois roll(0):

def test_gutter_game():
    game = bowling.Game()
    for roll in range(20):
        game.roll(0)
    score = game.score()
    assert score == 0


def test_all_ones():
    game = bowling.Game()
    for roll in range(20):
        game.roll(1)
    score = game.score()
    assert score == 20

Les tests continuent à passer. On peut maintenant réduire la duplication en introduisant une fonction roll_many :

def roll_many(game, count, value):
    for roll in range(count):
        game.roll(value)

def test_gutter_game():
    game = bowling.Game()
    roll_many(game, 20, 0)
    score = game.score()
    assert score == 0


def test_all_ones():
    game = bowling.Game()
    roll_many(game, 20, 1)
    score = game.score()
    assert score == 20
⁂RED⁂

L’algorithme utilisé (rajouter les quilles renversées au score à chaque lancer) semble fonctionner tant qu’il n’y a ni spare ni strike.

Du coup, rajoutons un test sur les spares :

def test_one_spare():
    game = bowling.Game()
    game.roll(5)
    game.roll(5)  # spare, next roll should be counted twice
    game.roll(3)
    roll_many(game, 17, 0)
    score = game.score()
    assert score == 16
        score = game.score()
>       assert score == 16
E       assert 13 == 16
⁂GREEN⁂

Et là, on se retrouve coincé. Il semble impossible d’implémenter la gestion des spares sans revoir le code de production en profondeur :

    def roll(self, pins):
        # TODO: get the knocked pin in the next
        # roll if we are in a spare ???
        self.knocked_pins += pins

C’est un état dans lequel on peut parfois se retrouver. La solution ? Faire un pas en arrière pour prendre du recul.

On peut commencer par désactiver le test qui nous ennuie :

import pytest


@pytest.mark.skip
def test_one_spare():
   ...

Ensuite, on peut regarder le code de production dans le blanc des yeux :

    def roll(self, pins):
        self.knocked_pins += pins

    def score(self):
        return self.knocked_pins

Ce code a un problème : en fait, c’est la méthode roll() qui calcule le score, et non la fonction score() !

On comprend que roll() doit simplement enregistrer l’ensemble des résultats des lancers, et qu’ensuite seulement, score() pourra parcourir les frames et calculer le score.

⁂REFACTOR⁂

On remplace donc l’attribut knocked_pins() par une liste de rolls et un index:

class Game:
    def __init__(self):
        self.rolls = [0] * 21
        self.roll_index = 0

    def roll(self, pins):
        self.rolls[self.roll_index] = pins
        self.roll_index += 1

    def score(self):
        result = 0
        for roll in self.rolls:
            result += roll
        return result

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)

  • spare: on va avoir droit à un un lancer en plus: 20 + 1 = 21
  • 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.
  • sinon: pas de lancer supplémentaire, on reste à 20 lancers.

Relançons les tests :

test_bowling.py ..s                                                      [100%]

===================== 2 passed, 1 skipped in 0.01 seconds ======================

(notez le ’s’ pour ‘skipped’)

L’algorithme est toujours éronné, mais on sent qu’on une meilleure chance de réussir à gérer les spares.

⁂RED⁂

On ré-active le test en enlevant la ligne @pytest.mark.skip et on retombe évidemment sur la même erreur :

>       assert score == 16
E       assert 13 == 16
⁂GREEN⁂

Pour faire passer le test, on peut simplement itérer sur les frames une par une, en utilisant une variable i qui vaut l’index du premier lancer de la prochaine frame :

    def score(self):
        result = 0
        i = 0
        for frame in range(10):
            if self.rolls[i] + self.rolls[i + 1] == 10:  # spare
                result += 10
                result += self.rolls[i + 2]
                i += 2
            else:
                result += self.rolls[i]
                result += self.rolls[i + 1]
                i += 2
        return result

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.

⁂REFACTOR⁂

Par contraste, ici on sait que l’algorithme est correct. Notre unique 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.

Bref, une façon de refactorer est d’introduire une nouvelle méthode :

    # note: i represents the index of the
    # first roll of the current frame
    def is_spare(self, i):
        return self.rolls[i] + self.rolls[i + 1] == 10

    def score(self):
        result = 0
        i = 0
        for frame in range(10):
            if self.is_spare(i):
                result += 10
                result += self.rolls[i + 2]
                i += 2
            else:
                result += self.rolls[i]
                result += self.rolls[i + 1]
                i += 2

En passant, on s’est débarrassé du commentaire “# spare” à la fin du if, vu qu’il n’était plus utile. En revanche, on a gardé un commentaire au-dessus de la méthode is_spare(). En effet, il n’est pas évident de comprendre la valeur représentée par l’index i juste en lisant le code. 7

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.

Mais avant cela, revenons sur les tests (règle 4) :

def test_one_spare():
    game = bowling.Game()
    game.roll(5)
    game.roll(5)  # spare, next roll should be counted twice
    game.roll(3)
    roll_many(game, 17, 0)
    score = game.score()
    assert score == 16

On a le même genre de commentaire qui nous suggère qu’il manque une abstraction quelque part : une fonction roll_spare.

import bowling
import pytest

def roll_many(game, count, value):
    for roll in range(count):
        game.roll(value)


def roll_spare(game):
    game.roll(5)
    game.roll(5)


def test_one_spare():
    game = bowling.Game()
    roll_spare(game)
    game.roll(3)
    roll_many(game, 17, 0)
    score = game.score()
    assert score == 16

Les tests continuent à passer, tout va bien.

Mais le code de test peut encore être amélioré. On voit qu’on a deux fonctions qui prennent chacune le même paramètre en premier argument.

Souvent, c’est le signe qu’une classe se cache quelque part.

On peut créer une classe GameTest qui hérite de Game et contient les méthodes roll_many() et roll_spare() :

import bowling
import pytest


class GameTest(bowling.Game):
    def roll_many(self, count, value):
        for roll in range(count):
            self.roll(value)

    def roll_spare(self):
        self.roll(5)
        self.roll(5)


def test_gutter_game():
    game = GameTest()
    game.roll_many(20, 0)
    score = game.score()
    assert score == 0


def test_all_ones():
    game = bowling.GameTest()
    game.roll_many(20, 1)
    score = game.score()
    assert score == 20


def test_one_spare():
    game = GameTest()
    game.roll_spare()
    game.roll(3)
    game.roll_many(17, 0)
    score = game.score()
    assert score == 16

Ouf! Suffisamment de refactoring pour l’instant, retour au rouge.

⁂RED⁂

Avec notre nouvelle classe définie au sein de test_bowling.py (on dit souvent “test helper”), on peut facilement rajouter le test sur les strikes :

class GameTest:
    ...
    def roll_spare(self):
        ...

    def roll_strike(self):
        self.roll(10)


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

A priori, tous les tests devraient passer sauf le dernier, et on devrait avoir une erreur de genre x != 24, avec x légèrement en-dessous de 24 :

________________________________ test_all_ones _________________________________

    def test_all_ones():
>       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()
>       assert score == 24
E       assert 17 == 24

test_bowling.py:48: AssertionError

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 : game = bowling.GameTest() au lieu de game = GameTest(). L’aviez-vous remarqué ?

Cela illustre deux points :

  1. Il faut toujours avoir une vague idée des tests qui vont échouer et de quelle manière
  2. Il est important de garder le cycle de TDD court. En effet, ici on sait que seuls les tests ont changé depuis la dernière session de test, donc on sait que le problème vient des tests et non du code de production.

On peut maintenant corriger notre faux positif, relancer les tests, vérifier qu’ils échouent pour la bonne raison et passer à l’étape suivante.

______________________________ 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()
>       assert score == 24
E       assert 17 == 24

test_bowling.py:48: AssertionError
⁂GREEN⁂

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 incrémentale, un petit bout à la fois.

class Game:
    ...

    def is_spare(self, i):
        return self.rolls[i] + self.rolls[i + 1] == 10

    def is_strike(self, i):
        return self.rolls[i] == 10

    def score(self):
        result = 0
        i = 0
        for frame in range(10):
            if self.is_strike(i):
                result += 10
                result += self.rolls[i + 1]
                result += self.rolls[i + 2]
                i += 1
            elif self.is_spare(i):
                result += 10
                result += self.rolls[i + 2]
                i += 2
            else:
                result += self.rolls[i]
                result += self.rolls[i + 1]
                i += 2
        return result

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 et les strikes en un seul morceau !

⁂REFACTOR⁂

On a maintenant une boucle avec trois 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 :

class Game:
    ...
    def is_strike(self, i):
        return self.rolls[i] == 10

    def is_spare(self, i):
        return self.rolls[i] + self.rolls[i + 1] == 10

    def next_two_rolls_for_strike(self, i):
        return self.rolls[i + 1] + self.rolls[i + 2]

    def next_roll_for_spare(self, i):
        return self.rolls[i + 2]

    def rolls_in_frame(self, i):
        return self.rolls[i] + self.rolls[i + 1]

    def score(self):
        result = 0
        i = 0
        for frame in range(10):
            if self.is_strike(i):
                result += 10
                result += self.next_two_rolls_for_strike(i)
                i += 1
            elif self.is_spare(i):
                result += 10
                result += self.next_roll_for_spare(i)
                i += 2
            else:
                result += self.rolls_in_frame(i)
                i += 2
        return result

On approche du but, il ne reste plus qu’à gérer la dernière frame.

⁂RED⁂

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

Et comme tout joueur de bowling le sait, le score maximum au bowling est 300 :

def test_perfect_game():
    game = GameTest()
    for i in range(0, 12):
        game.roll_strike()
    assert game.score() == 300

On lance les tests, et…

collected 5 items

test_bowling.py .....                                                          [100%]
============================= 5 passed in 0.02 seconds ==============================

Ils passent ?

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.

Conclusions #

D’abord, je trouve qu’on peut être fier du code auquel on a abouti :

        result = 0
        i = 0
        for frame in range(10):
            if self.is_strike(i):
                result += 10
                result += self.next_two_rolls_for_strike(i)
                i += 1
            elif self.is_spare(i):
                result += 10
                result += self.next_roll_for_spare(i)
                i += 2
            else:
                result += self.rolls_in_frame(i)
                i += 2

Le code se “lit” quasiment comme les règles du bowling. Il a l’air correct, et il est correct.

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 Frame ou Roll, ni de la classe fille TenthFrame. En ce sens, on peut dire que TDD est également une façon de concevoir le code, et pas juste une façon de faire évoluer le code de production et le code de test en parallèle.

Enfin, on avait un moyen de savoir quand le code était fini. 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 uniquement le code nécessaire.

Pour aller plus loin #

Plusieurs remarques :

1/ La méthode roll() peut être appelée un nombre trop grand de fois, comme le prouve le test suivant :

def test_two_many_rolls():
   game = GameTest()
   game.roll_many(21, 1)
   assert game.score() == 20

Savoir si c’est un bug ou non dépend des spécifications.

2/ Il y a probablement une classe ou une méthode cachée dans la classe Game. 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.

Résoudre ces deux problèmes sera laissé en exercice au lecteur :P

Conclusion #

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.

À +


  1. C’est payant, c’est en anglais, les exemples sont en Java, mais c’est vraiment très bien. ↩︎

  2. Par exemple, quand on lance python avec l’option -O ↩︎

  3. Voir cet article pour comprendre pourquoi on procède ansi. ↩︎

  4. Il existe de nombreux outils pour palier aux limitations des tests, mais on en parlera une prochaine fois. ↩︎

  5. Les trois premières règles sont de Uncle Bob, la dernière est de moi. ↩︎ ↩︎

  6. 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 devez passer à l’anglais. ↩︎

  7. Si cette façon de commenter du code vous intrigue, vous pouvez lire cet excellent article (en anglais) pour plus de détails. ↩︎

Lire la suite…

Porter un gros project vers Python3

by Le blog de Dim' from Le blog de Dim'

Port d’un gros projet vers Python3 - Retour d’expérience #

Introduction : le projet en question #

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

  • la taille du projet: un peu moins de 30,000 lignes de code, et
  • l’ancienneté du code: près de 6 ans, qui initialement a tourné avec Python 2.6 (eh oui)

Le challenge #

On veut garder la rétro-compat vers Python2.7, histoire que la transition se fasse en douceur.

On veut aussi pouvoir continuer les développements en Python2 sans attendre la fin du port.

À faire avant de commencer à porter #

Visez la bonne version de Python #

Déjà, si vous supportez à la fois Python2 et Python3, vous pouvez (et devez) ignorer les versions de Python comprises entre 3.0 et 3.2 inclus.

Les utilisateurs de distros “archaïques” (genre Ubuntu 12.04) avec un vieux Python3 pourront tout à fait continuer à utiliser la version Python2.

Ayez une bonne couverture de tests #

Ne vous lancez pas dans le port sans une bonne couverture de tests.

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.

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)

Le port proprement dit #

Marche à suivre #

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

  1. Lancez 2to3 et faites un commit avec le patch généré
  2. Lancez les tests en Python3 jusqu’à ce qu’ils passent tous
  3. Relancez tous les tests en Python2, en utilisant six pour rendre le code polyglotte.
  4. Assurez vous que tous les tests continuent à passer en Python3, commitez et poussez.

Note 1 : je ne connaissais pas python-future à l’époque. Il contient un outil appelé futurize qui transforme directement du code Python2 en code polyglotte. Si vous avez des retours à faire sur cet outil, partagez !

Note 2 : Vous n’êtes bien sûr pas obligés d’utiliser six si vous n’avez pas envie. Vous pouvez vous en sortir avec des if sys.version_info()[1] < 3, et autres from __future__ import (voir plus bas). Mais certaines fonctionnalités de six sont compliquées à ré-implémenter à la main.

Note 3 : il existe aussi pies comme alternative à six. Voir ici pour une liste des différences avec six. Personnellement, je trouve pies un peu trop “magique” et je préfère rester explicite. De plus, six semble être devenu le “standard” pour le code Python polyglotte.

Voyons maintenant quelques exemples de modifications à effectuer.

print #

C’est le changement qui a fait le plus de bruit. Il est très facile de faire du code polyglotte quand on utilise print. Il suffit de faire le bon import au début du fichier.

from __future__ import print


print("bar:", bar)

Notes:

  • L’import de __future__ doit être fait en premier

  • Il faut le faire sur tous les fichiers qui utilisent print

  • Il est nécessaire pour avoir le même comportement en Python2 et Pyton3. En effet, sans la ligne d’import, print("bar:", "bar") en Python2 est lu comme “afficher le tuple ("foo", bar)”, ce qui n’est probablement pas le comportement attendu.

bytes, str, unicode #

Ça c’est le gros morceau.

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” (str en Python2, bytes en Python3) ou “décodée” (unicode en Python2, str en Python3)

Deux articles de Sam qui abordent très bien la question:

Allez les (re)-lire si c’est pas déjà fait.

En résumé :

  • Utilisez UTF-8
  • Décodez toutes les entrées
  • Encodez toutes les sorties

J’ai vu conseiller de faire from __future__ import unicode_literals:

# avec from __future__ import unicode_literals
a = "foo"
>>> type(a)
<type 'unicode'>

# sans
a = "foo"
>>> type(a)
<type 'str'>

Personnellement je m’en suis sorti sans. À vous de voir.

Les imports relatifs et absolus #

Personnellement, j’ai tendance à n’utiliser que des imports absolus.

Faisons l’hypothèse que vous avez installé un module externe bar, dans votre système (ou dans votre virtualenv) et que vous avez déjà un fichier bar.py dans vos sources.

Les imports absolus ne changent pas l’ordre de résolution quand vous n’êtes pas dans un paquet. Si vous avez un fichier foo.py et un fichier bar.py côte à côte, Python trouvera bar dans le répertoire courant.

En revanche, si vous avec une arborescence comme suit :

src
  foo
      __init__.py
      bar.py

Avec

# in foo/__init__.py
import bar

En Python2, c’est foo/bar.py qui sera utilisé, et non lib/site-packages/bar.py. En Python3 ce sera l’inverse, le fichier bar.py, relatif à foo/__init__ aura la priorité.

Pour vous éviter ce genre de problèmes, utilisez donc :

from __future__ import absolute_import

Ou bien rendez votre code plus explicite en utilisant un point :

from . import bar

Vous pouvez aussi:

  • Changer le nom de votre module pour éviter les conflits.
  • Utiliser systématiquement import foo.bar (C’est ma solution préférée)

La division #

Même principe que pour print. Vous pouvez faire

from __future__ import division

et / fera toujours une division flottante, même utilisé avec des entiers.

Pour retrouver la division entière, utilisez //.

Example:

>>> 5/2
>>> 2.5

>>> 3

Note: celui-ci est assez vicieux à détecter …

Les changements de noms #

De manière générale, le module six.moves contient tout ce qu’il faut pour résoudre les problèmes de changement de noms.

Allez voir la table des cas traités par six ici

six 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)

Avec six, vous pouvez écrire

@six.add_metaclass(Meta)
class Foo:
    pass

range et xrange #

En Python2, range() est “gourmand” et retourne la liste entière dès qu’on l’appelle, alors qu’en Python3, range() est “feignant” et retourne un itérateur produisant les éléments sur demande. En Python2, si vous voulez un itérateur, il faut utiliser xrange().

Partant de là, vous avez deux solutions:

  • Utiliser range tout le temps, même quand vous utilisiez xrange en Python2. Bien sûr il y aura un coût en performance, mais à vous de voir s’il est négligeable ou non.

  • Ou bien utiliser six.moves.range() qui vous retourne un itérateur dans tous les cas.

import six

my_iterator = six.moves.range(0, 3)

Les “vues” des dictionnaires #

On va prendre un exemple:

my_dict = { "a" : 1 }
keys = my_dict.keys()

Quand vous lancez 2to3, ce code est remplacé par:

my_dict = { "a" : 1 }
keys = list(my_dict.keys())

C’est très laid :/

En fait en Python3, keys() retourne une “vue”, ce qui est différent de la liste que vous avez en Python2, mais qui est aussi différent de l’itérateur que vous obtenez avec iterkeys() en Python2. En vrai ce sont des view objects.

La plupart du temps, cependant, vous voulez juste itérer sur les clés et donc je recommande d’utiliser 2to3 avec --nofix=dict.

Bien sûr, keys() est plus lent en Python2, mais comme pour range vous pouvez ignorer ce détail la plupart du temps.

Faites attention cependant, le code plantera si vous faites :

my_dict = { "a" : 1 }
keys = my_dict.keys()
keys.sort()

La raison est que les vues n’ont pas de méthode sort. À la place, utilisez :

my_dict = { "a" : 1 }
keys = sorted(my_dict.keys())

Enfin, il existe un cas pathologique : celui où le dictionnaire change pendant que vous itérez sur les clés, par exemple:

for key in my_dict.keys():
    if something(key):
        del my_dict[key]

Là, pas le choix, il faut faire :

for key in list(my_dict.keys()):
    if something(key):
        del my_dict[key]

Ou

for key in list(six.iterkeys(my_dict)):
    if something(key):
        del my_dict[key]

si vous préférez.

Les exceptions #

En Python2, vous pouvez toujours écrire:

raise MyException, message

try:
    # ....
except MyException, e:
    # ...
    # Do something with e.message

C’est une très vielle syntaxe.

Le code peut être réécrit comme suit, et sera polyglotte :

raise MyException(message)

try:
    # ....
except MyException as e:
    # ....
    # Do something with e.args

Notez l’utilisation de e.args (une liste), et non e.message. L’attribut message (une string) n’existe que dans Python2. Vous pouvez utiliser .args[0] pour récupérer le message d’une façon polyglotte.

Comparer des pommes et des bananes #

En Python2, tout est ordonné:

>>> print sorted(["1", 0, None])
[None, 0, "1"]

L’interpréteur n’a aucun souci avec le fait que vous tentiez d’ordonner une string et un nombre.

En Python3, ça crashe:

TypeError: '<' not supported between instances of 'int' and 'str'

Pensez y si vous avez des tris sur des classes à vous. La technique recommandée c’est d’utiliser @functools.total_ordering et de définir __lt__:

@functools.total_ordering
class MaClassPerso():
    ...

    def __lt__(self, other):
        return self.quelque_chose < other.quelque_chose

Le ficher setup.py #

Assurez vous de spécifier les versions de Python supportées dans votre setup.py

Par exemple, si vous supportez à la fois Python2 et Python3, utilisez :


from setuptools import setup, find_packages

setup(name="foo",
      # ...
      classifiers = [
        # ...
        "Programming Language :: Python :: 2",
        "Programming Language :: Python :: 3",
      ],
      # ...
)

Et ajoutez un setup.cfg comme suit :

[bdist_wheel]
universal = 1

pour générer une wheel compatible Python2 et Python3.

Deux trois mots sur l’intégration continue #

Comme mentionné plus haut, le développement du projet a dû continuer sans attendre que le support de Python3 soit mergé.

Le port a donc dû se faire dans une autre branche (que j’ai appelé six)

Du coup, comment faire pour que la branche ‘six’ reste à jour ?

La solution passe par l’intégration continue. Dans mon cas j’utilise jenkins

À chaque commit sur la branche de développement, voici ce qu’il se passe:

  • La branche ‘six’ est rebasée
  • Les tests sont lancés avec Python2 puis Python3
  • La branche est poussée (avec --force).

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.

Ainsi la branche six continue d’être “vivante” et il est trivial et sans risque de la fusionner dans la branche de développement au moment opportun.

Conclusion #

J’aimerais remercier Eric S. Raymond qui m’a donné l’idée de ce billet suite à un article sur son blog et m’a autorisé à contribuer à son HOWTO, suite à ma réponse

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.

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 !

Lire la suite…

Utiliser des bibliothèques tierces avec Python

by Le blog de Dim' from Le blog de Dim'

Note : cet article reprend en grande partie le cours donné à l’École du Logiciel Libre le 4 mai 2019.

Quelques rappels pour commencer.

Importer un module #

Soit le code suivant :

import foo
foo.bar()

Ce code fonctionne s’il y a un ficher foo.py quelque part qui contient la fonction bar 1

Ce fichier peut être présent soit dans le répertoire courant, soit dans la bibliothèque standard Python.

La variable PATH #

Vous connaissez peut-être le rôle de la variable d’environnement PATH. Celle-ci contient une liste de chemins, et est utilisée par votre shell pour trouver le chemin complet des commandes que vous lancez.

Par exemple:

PATH="/bin:/usr/bin:/usr/sbin"
$ ifconfig
# lance le binaire /usr/sbin/ifconfig
$ ls
# lance le binaire /bin/ls

Le chemin est “résolu” par le shell en parcourant la liste de tout les segments de PATH, et en regardant si le chemin complet existe. La résolution s’arrête dès le premier chemin trouvé.

Par exemple, si vous avez PATH="/home/user/bin:/usr/bin" et un fichier ls dans /home/user/bin/ls, c’est ce fichier-là (et non /bin/ls) qui sera utilisé quand vous taperez ls.

sys.path #

En Python, il existe une variable path prédéfinie dans le module sys qui fonctionne de manière similaire.

Si j’essaye de l’afficher sur mon Arch Linux, voici ce que j’obtiens :

>>> import sys
>>> sys.path
[
 "",
 "/usr/lib/python3.7",
 "/usr/lib/python3.7/lib-dynload",
 "/home/dmerej/.local/lib/python3.7/",
 "/usr/lib/python3.7/site-packages",
]

Notez que le résultat dépend de ma distribution, et de la présence ou non du répertoire ~/.local/lib/python3.7/ sur ma machine - cela prouve que sys.path est construit dynamiquement par l’interpréteur Python.

Notez également que sys.path commence par une chaîne vide. En pratique, cela signifie que le répertoire courant a la priorité sur tout le reste.

Ainsi, si vous avez un fichier random.py dans votre répertoire courant, et que vous lancez un script foo.py dans ce même répertoire, vous vous retrouvez à utiliser le code dans random.py, 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 la documentation.

Un autre aspect notable de sys.path est qu’il ne contient que deux répertoires dans lesquels l’utilisateur courant peut potentiellement écrire : le chemin courant et le chemin dans ~/.local/lib. Tous les autres (/usr/lib/python3.7/, etc.) sont des chemins “système” et ne peuvent être modifiés que par un compte administrateur (avec root ou sudo, donc).

La situation est semblable sur macOS et Windows 2.

Bibliothèques tierces #

Prenons un exemple :

# dans foo.py
import tabulate

scores = [
  ["John", 345],
  ["Mary-Jane", 2],
  ["Bob", 543],
]
table = tabulate.tabulate(scores)
print(table)
$ python3 foo.py
---------  ---
John       345
Mary-Jane    2
Bob        543
---------  ---

Ici, le module tabulate n’est ni dans la bibliothèque standard, ni écrit par l’auteur du script foo.py. On dit que c’est une bibliothèque tierce.

On peut trouver le code source de tabulate facilement. La question qui se pose alors est: comment faire en sorte que sys.path contienne le module tabulate?

Eh bien, plusieurs solutions s’offrent à vous.

Le gestionnaire de paquets #

Si vous utilisez une distribution Linux, peut-être pourrez-vous utiliser votre gestionnaire de paquets :

$ sudo apt install python3-tabulate

Comme vous lancez votre gestionnaire de paquets avec sudo, celui-ci sera capable d’écrire dans les chemins système de sys.path.

À la main #

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.

Voici une marche à suivre possible :

  1. Récupérer les sources de la version qui vous intéresse dans la section téléchargement de bitbucket.
  2. Extraire l’archive, par exemple dans src/tabulate
  3. Se rendre dans src/tabulate et lancer python3 setup.py install --user

Anatomie du fichier setup.py #

La plupart des bibliothèques Python contiennent un setup.py à la racine de leurs sources. Il sert à plein de choses, la commande install n’étant qu’une parmi d’autres.

Le fichier setup.py contient en général simplement un import de setuptools, et un appel à la fonction setup(), avec de nombreux arguments :

# tabulate/setup.py
from setuptools import setup

setup(
  name='tabulate',
  version='0.8.1',
  description='Pretty-print tabular data',
  py_modules=["tabulate"],
  scripts=["bin/tabulate"],
  ...
)

Résultat de l’invocation de setup.py #

Par défaut, setup.py essaiera d’écrire dans un des chemins système de sys.path 3, d’où l’utilisation de l’option --user.

Voici à quoi ressemble la sortie de la commande :

$ cd src/tabulate
$ python3 setup.py install --user
running install
...
Copying tabulate-0.8.4-py3.7.egg to /home/dmerej/.local/lib/python3.7/site-packages
...
Installing tabulate script to /home/dmerej/.local/bin

Notez que module a été copié dans ~/.local/lib/python3.7/site-packages/ et le script dans ~/.local/bin. Cela signifie que tous les scripts Python lancés par l’utilisateur courant auront accès au module tabulate.

Notez également qu’un script a été installé dans ~/.local/bin - Une bibliothèque Python peut contenir aussi bien des modules que des scripts.

Un point important est que vous n’avez en général pas besoin de lancer le script directement. Vous pouvez utiliser python3 -m tabulate. 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.

Dépendances #

Prenons une autre bibliothèque : cli-ui.

Elle permet d’afficher du texte en couleur dans un terminal

import cli_ui

cli_ui.info("Ceci est en", cli_ui.red, "rouge")

Elle permet également d’afficher des tableaux en couleur :

headers=["name", "score"]
data = [
  [(bold, "John"), (green, 10.0)],
  [(bold, "Jane"), (green, 5.0)],
]
cli_ui.info_table(data, headers=headers)

Pour ce faire, elle repose sur la bibliothèque tabulate vue précédemment. On dit que cli-ui dépend de tabulate.

Déclaration des dépendances #

La déclaration de la dépendance de cli-ui vers tabulate s’effectue également dans le fichier setup.py:

setup(
  name="cli-ui",
  version="0.9.1",
  install_requires=[
     "tabulate",
     ...
  ],
  ...
)

pypi.org #

On comprend dès lors qu’il doit nécessairement exister un annuaire permettant de relier les noms de dépendances à leur code source.

Cet annuaire, c’est le site pypi.org. Vous y trouverez les pages correspondant à tabulate et cli-ui.

pip #

pip est un outil qui vient par défaut avec Python34. Vous pouvez également l’installer grâce au script get-pip.py, en lançant python3 get-pip.py --user.

Il est conseillé de toujours lancer pip avec python3 -m pip. De cette façon, vous êtes certains d’utiliser le module pip correspondant à votre binaire python3, et vous ne dépendez pas de ce qu’il y a dans votre PATH.

pip est capable d’interroger le site pypi.org pour retrouver les dépendances, et également de lancer les différents scripts setup.py.

Comme de nombreux outils, il s’utilise à l’aide de commandes. Voici comment installer cli-ui à l’aide de la commande ‘install’ de pip:

$ python3 -m pip install cli-ui --user
Collecting cli-ui
...
Requirement already satisfied: unidecode in /usr/lib/python3.7/site-packages (from cli-ui) (1.0.23)
Requirement already satisfied: colorama in /usr/lib/python3.7/site-packages (from cli-ui) (0.4.1)
Requirement already satisfied: tabulate in /mnt/data/dmerej/src/python-tabulate (from cli-ui) (0.8.4)
Installing collected packages: cli-ui
Successfully installed cli-ui-0.9.1

On constate ici quelques limitations de pip:

  • Il faut penser à utiliser --user (de la même façon que lorsqu’on lance setup.py à la main)
  • 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

En revanche, pip contient de nombreuses fonctionnalités intéressantes:

  • Il est capable de désinstaller des bibliothèques (à condition toutefois qu’elles ne soient pas dans un répertoire système)
  • Il est aussi capable d’afficher la liste complète des bibliothèques Python accessibles par l’utilisateur courant avec freeze.

Voici un extrait de la commande python3 -m pip freeze au moment de la rédaction de cet article sur ma machine:

$ python3 -m pip freeze
apipkg==1.5
cli-ui==0.9.1
gaupol==1.5
tabulate==0.8.4

On y retrouve les bibliothèques cli-ui et tabulate, bien sûr, mais aussi la bibliothèque gaupol, qui correspond au programme d’édition de sous-titres 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.

On constate également que chaque bibliothèque possède un numéro de version.

Numéros de version #

Les numéros de version remplissent plusieurs rôles, mais l’un des principaux est de spécifier des changements incompatibles.

Par exemple, pour cli-ui, la façon d’appeler la fonction ask_choice a changé entre les versions 0.7 et 0.8, comme le montre le changelog:

the list of choices used by ask_choice is now a named keyword argument:

# Old (<= 0.7)
ask_choice("select a fruit", ["apple", "banana"])
# New (>= 0.8)
ask_choice("select a fruit", choices=["apple", "banana"])

Ceci s’appelle un changement d’API.

Réagir aux changements d’API #

Plusieurs possibilités:

  • On peut bien sûr adapter le code pour utiliser la nouvelle API, mais cela n’est pas toujours possible ni souhaitable.
  • Une autre solution est de spécifier des contraintes sur le numéro de version dans la déclaration des dépendances. Par exemple :
setup(
  install_requires=[
    "cli-ui < 0.8",
    ...
  ]
)

Aparté : pourquoi éviter sudo pip #

Souvenez-vous que les fichiers systèmes sont contrôlés par votre gestionnaire de paquets.

Les mainteneurs de votre distribution font en sorte qu’ils fonctionnent bien les uns avec les autres. Par exemple, le paquet python3-cli-ui ne sera mis à jour que lorsque tous les paquets qui en dépendent seront prêts à utiliser la nouvelle API.

En revanche, si vous lancez sudo pip (où pip avec un compte root), vous allez écrire dans ces mêmes répertoire et vous risquez de “casser” certains programmes de votre système.

Mais il y a un autre problème encore pire.

Conflit de dépendances #

Supposons deux projets A et B dans votre répertoire personnel. Ils dépendent tous les deux de cli-ui, mais l’un des deux utilise cli-ui 0.7 et l’autre cli-ui 0.9. Que faire ?

Environnements virtuels #

La solution est d’utiliser un environnement virtuel (virtualenv en abrégé). C’est un répertoire isolé du reste du système.

Pour créer un virtualenv il faut utiliser la commande:

$ python -m venv /chemin/vers/virtualenv

/chemin/vers/virtualenv est le dossier cible. Les dossiers parents seront créés si nécessaire par le module venv.

En pratique, on préfère utiliser un chemin qui n’existe pas encore, typiquement :

$ cd /chemin/vers/project
$ python -m .venv

Ici on a utilisé le répertoire relatif .venv.

Aparté : python3 -m venv sur Debian #

La commande python3 -m venv fonctionne en général partout, dès l’installation de Python3 (out of the box, en Anglais), sauf sur Debian et ses dérivées 5.

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 :

  • installant le paquet python3-venv,
  • ou en utilisant d’abord pip pour installer virtualenv, avec python3 -m pip install virtualenv --user puis en lançant python3 -m virtualenv foo-venv.

Comportement de python dans le virtualenv #

Ce répertoire contient de nombreux fichiers et dossiers, et notamment un binaire dans foo-venv/bin/python3.

Voyons comment il se comporte en le comparant au binaire /usr/bin/python3 habituel :

$ /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,
]

À noter:

  • Le répertoire “global” dans ~/.local/lib a disparu
  • Seuls quelques répertoires systèmes sont présents (ils correspondent plus ou moins à l’emplacement des modules de la bibliothèque standard)
  • Un répertoire au sein du virtualenv a été rajouté

Ainsi, l’isolation du virtualenv est reflété dans la différence de la valeur de sys.path.

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.

Par exemple, si vous utilisez /usr/local/bin/python3.7 -m venv foo-37, le virtualenv dans foo-37 utilisera Python 3.7 et fonctionnera tant que le binaire /usr/local/bin/python3.7 existe.

Cela signifie également qu’il est possible qu’en mettant à jour le paquet python3 sur votre distribution, vous rendiez inutilisables les virtualenvs créés avec l’ancienne version du paquet.

Comportement de pip dans le virtualenv #

D’après ce qui précède, le virtualenv ne devrait contenir aucun module en dehors de la bibliothèque standard et de pip lui-même.

On peut s’en assurer en lançant python3 -m pip freeze depuis le virtualenv et en vérifiant que rien ne s’affiche.

$ 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 :)

On peut alors utiliser le module pip du virtualenv pour installer des bibliothèques dans celui-ci :

$ /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

Cette fois, aucune bibliothèque n’est marquée comme déjà installée, et on récupère donc cli-ui et toutes ses dépendances.

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 cli-ui, isolées les unes des autres.

Activer un virtualenv #

Devoir préciser le chemin du virtualenv en entier pour chaque commande peut devenir fastidieux ; heureusement, il est possible d’activer un virtualenv, en lançant une des commandes suivantes :

  • source foo-venv/bin/activate - si vous utilisez un shell POSIX
  • source foo-venv/bin/activate.fish - si vous utilisez Fish
  • foo-venv\bin\activate.bat - sous Windows

Une fois le virtualenv activé, taper python, python3 ou pip utilisera les binaires correspondants dans le virtualenv automatiquement, et ce, tant que la session du shell sera ouverte.

Le script d’activation ne fait en réalité pas grand-chose à part modifier la variable PATH et rajouter le nom du virtualenv au début de l’invite de commandes :

# Avant
user@host:~/src $ source foo-env/bin/activate
# Après
(foo-env) user@host:~/src $

Pour sortir du virtualenv, entrez la commande deactivate.

Conclusion #

Le système de gestions des dépendances de Python peut paraître compliqué et bizarre, surtout venant d’autres langages.

Mon conseil est de toujours suivre ces deux règles :

  • Un virtualenv par projet et par version de Python
  • Toujours utiliser pip depuis un virtualenv

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

Dans un futur article, nous approfondirons la question, en évoquant d’autres sujets comme PYTHONPATH, le fichier requirements.txt ou des outils comme poetry ou pipenv. À suivre.


  1. C’est une condition suffisante, mais pas nécessaire - on y reviendra. ↩︎

  2. Presque. Il peut arriver que l’utilisateur courant ait les droits d’écriture dans tous les segments de sys.path, en fonction de l’installation de Python. Cela dit, c’est plutôt l’exception que la règle. ↩︎

  3. 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. ↩︎

  4. Presque. Parfois il faut installer un paquet supplémentaire, notamment sur les distributions basées sur Debian ↩︎

  5. 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. 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. ↩︎

Lire la suite…

Bonjour, monde

by Le blog de Dim' from Le blog de Dim'

Bonjour à tous et bienvenue !

Cet article est le premier d’un tout nouveau blog (sur https://dmerej.info/blog/fr), contenant exclusivement des articles en français.

Notez l’existence de mon blog anglophone, qui est disponible sur https://dmerej.info/blog. 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 ?

Sans plus attendre, vous pouvez lire mon premier article sur Python et les bibliothèques tierces.

Lire la suite…