PROJET AUTOBLOG


Sam & Max

Site original : Sam & Max

⇐ retour index

Mise à jour

Mise à jour de la base de données, veuillez patienter...

Vive setup.cfg (et mort à pyproject.toml) ! 1

Thursday 6 December 2018 à 11:07

Après un long débat sur hackernews, qui n’est que le reflet de toutes les conversations que j’ai déjà eues à ce sujet sur twitter, github, et divers mailling lists, il est grand temps de faire un article. Urgent même.

Est-ce que vous savez quel chemin de croix on a vécu avec le packaging Python durant ces 15 dernières années ?

D’abord on a distutils, setuptools, distribute, and distribute2 qui ont tous été à un moment les “standards” recommandés pour packager une lib. Ensuite on a eu l’époque des eggs, exe, et autres trucs que easy_install allait chercher n’importe où dans la nature en suivant aveuglément des liens sur PyPi. Sans compter les machins qu’il fallait compiler à tout bout de champ. Et puis rien n’était chiffré au download, pip n’était pas packagé avec Python, il crevait sur des erreurs stupides type encodage mal géré…

À ça se rajoute que virtualenv était un truc à part, avec plein de concurrents, et linkait les packages système par défaut. Sans oublier qu’on avait pas Python -m.

Bref, le packaging Python, ça a été vraiment la merde. Avec en plus une doc de merde.

Aujourd’hui, le standard wheel a énormément amélioré la donne. On a des tutos corrects (ex: notre tuto sur comment créer son package avec setup.py). ensurepip fait qu’on a une version récente du truc presque partout.

En gros, notre situation est stable, saine. Améliorable de bien des façons, certes, mais un bon socle sur lequel s’appuyer.

Arrive setup.cfg

En 2016, l’équipe de setuptools, la lib utilisée par à peu près tout le monde pour créer des packages en Python aujourd’hui, a créé le format setup.cfg, un fichier INI dont le but est de remplacer setup.py.

Le problème de setup.py c’est que c’est du code Python exécutable, et en plus dépendant de la lib setuptools. Cela empêche non seulement l’interfaçage avec des outils externes, mais aussi freine l’émergence de nouveaux outils.

En effet, il y a un désir de continuer à améliorer la situation du packaging en Python, comme on peut le voir avec des projets comme pipenv ou poetry (je recommande d’ailleurs fortement ce dernier, et je vous invite à voter sur cette issue pour enfoncer le clou).

setup.cfg est la suite logique de tout ça, un format en texte brut, facile à manipuler pour le reste du monde.

Et ça a été bien fait:

Donc setup.cfg, malgré des lacunes, c’est sympa.

Setup.cfg, ou es-tu ?

“Attend une minute, si c’est si bien que ça, pourquoi j’en ai jamais entendu parler ? Moi on m’a dit que setup.cfg il servait à rien…”

Je ne vous le fais pas dire !

Je n’ai aucune idée de la raison pour laquelle cette information ne circule pas plus. La seule raison pour laquelle je l’ai trouvée c’est parce que je passe des heures à faire de la veille informationnelle en Python, et que je suis tombé dessus au détour d’un carrefour, dans une ruelle sombre du Web. Et que j’ai pris le temps et le risque de le tester sur un de mes projets pour vérifier que oui, ça marche comme prévu.

Même la doc Python vous fait croire que setup.cfg c’est un artéfact vaguement utile pour une pauvre option monoligne.

Et merde, j’ai déjà écrit 900 articles sur ce blog, je ne peux pas mettre à ma charge d’avertir tout le monde pour chaque truc à savoir sur Python.

C’est comme pour le # -*- coding: utf-8 -*-. Un jour un mec utilisant Emacs a écrit un tuto avec ça, et tout le monde a copié-collé les hiéroglyphes alors qu’en fait # coding: utf8 est parfaitement valide. Ou comme nuikta, qui permet de compiler de Python de manière fiable, et que personne ne connait. Combien de temps doit-on gâcher avec des trucs comme ça ?

pyproject.toml vient foutre le bordel

Maintenant, figurez-vous que nous avons un groupe de personne chargée de faire évoluer la situation du packaging, la Python Packaging Authority, ou PyPA.

Une très bonne initiative, vu que le free-for-all du passé ne nous avait pas trop réussi. Et un succès puisque la situation actuelle en packaging Python est maintenant beaucoup plus propre.

Et on en a besoin. En effet, setup.cfg doit être amélioré car il a certains défauts. Le format n’est pas parfaitement standardisé. Seule la doc fait figure de description, et pour l’instant setup.cfg, c’est whatever configparser comprends, sachant que configparser parse les trucs au motoculteur, et selon la version de Python. C’est pas gravissime, et ça n’a pas vraiment été un problème jusque là, mais pour la pérennité de la chose, une consolidation est nécessaire. On doit avoir une spec solide, un parseur robuste et stable, etc.

Sachant la purge qu’a été l’historique du packaging en Python, on s’attend donc a ce que la PyPA fasse le choix de standardiser setup.cfg, qui marche depuis 2 ans, fait le job, est compatible avec l’existant et résout déjà le problème de permettre au reste du monde de manipuler les données du package en texte brut. Puis, comme un bon groupe de décision sage, elle va proposer des solutions incrémentales aux défauts de setup.cfg et son écosystème.

Un exemple possible serait de s’allier avec l’équipe de setuptools pour figer le format setup.cfg, clarifier les edge cases de ce INI en particulier, et si besoin, créer une alternative a configparser (ou figer configparser) afin d’obtenir une implémentation de référence irréprochable pour parser le format. Puis désigner ce format comme le nouveau standard, en version 1 implicite, et le documenter puis en faire la promotion afin que tous les nouveaux outils puissent l’utiliser. Ensuite, ayant identifié des limitations, on crée le successeur de ce format, qui aura le même nom, mais un header de version qui lui sera explicite afin de permettre aux parseurs de s’adapter. Et on fait en sorte que cette nouvelle version soit plus propre, plus belle, super green. Et on l’introduit aussi progressivement et en douceur qu’un sex toy anal.

Bref, on s’attend à ce que la PyPA nous amène vers une totale liberté de pensée cosmique vers un nouvel âge réminiscence.

Sauf que non.

Ces ânes ont décidé… de créer un nouveau format et ignorer tout l’existant.

Fuck. That. Je hais que ce dessin de XKCD puisse être d’actualité encore et encore, chaque mois que l’humanité passe:
Le packaging en Python, c'est une forme de solidarité masochiste avec la communauté JS

Je ne comprends pas cette décision, et leurs justifications sont d’une grande faiblesse, pour ne pas dire insultante pour une communauté qui en a marre de payer le prix de l’égo des gens qui ont envie d’avoir leur nom sur la nouvelle barre de fer officielle.

C’est d’autant plus étrange que la PyPA n’est pas composée de cons. Non. On a Brett Cannon (core dev, qui fait un travail exceptionnel avec Python VSCode), Nathaniel Smith (qui nous a révolutionné l’async avec trio) et Kenneth Reitz (l’auteur de Python requests).

Comment ce pet de cerveau a-t-il pu émané de ces brillantes personnes, je ne le sais.

Mais je vous invite tous à non seulement utiliser setup.cfg en masse, mais aussi à activement contester cette décision sur tous les mediums à votre disposition.

Parce qu’évidemment je l’ai fais, et comme d’hab, ils font la sourde oreille. Et on va en payer le prix. Mais bon, depuis le temps, vous avez l’habitude. C’est pas comme si j’avais pas déjà annoncé que redux et dockers étaient overkill pour la plupart des projets, que le NoSQL allait avoir un retour de baton, que vue était génial, flask PAS pour les débutants, bitcoin intéressant, pipenv –three stupide, python parfait pour l’enseignement… des années avant. Pour les consultations de boule de cristal, c’est uniquement le mardi à 15h.

N’est-ce pas trop tard ?

Au contraire, c’est exactement le bon moment. Le format le plus utilisé actuellement n’est ni le setup.cfg, ni le pyproject.toml, mais toujours le bon vieux setup.py. En fait, n’en déplaise aux defenseurs de pyproject.toml qui veulent nous faire croire que le projet est bien plus populaire et avancé qu’il ne l’est vraiment, il vaut l’équivalent d’un draft de proposal en beta testing. Une simple recherche github retourne:

De toute façon la transition sera longue, et les outils commencent à peine à supporter le nouveau format. En fait, ils ne sont même pas d’accord sur comment l’utiliser. On a pas de standard pour le lock file (pipfile semble se dégager, mais n’est pas enterriné) et les outils utilisent pyproject.toml en créant une section custo dedans au lieu des champs standardisés (poetry), voir par du tout comme pipenv. De plus, setup.cfg est déjà utilisé dans la nature (voir les exemple plus haut).

Par ailleurs, extraire les données de setup.cfg plutôt que de pyproject.toml n’est pas très compliqué, les outils de packaging n’ont qu’une toute petite partie de leur code dédié à la gestion du fichier, le reste c’est la logique de management des dépendances, le téléchargement, la command line, le virtualenv, etc. Ils peuvent par ailleurs tout à fait supporter les deux pendant la transition.

Vu que c’est nous qui allons nous coltiner les conséquences du choix pour les 10 prochaines années à venir, autant élever la voir. D’autant que, surprise, ça ne coûte quasiment rien à la majorité des projets de migrer ou commencer avec setup.cfg. Tout marche déjà, et on peut prouduire de jolies wheels. On ne peut pas dire autant de pyproject qui demande d’adopter des outils tout neufs et qui doivent encore faire leur preuve. Aussi, bonne chance pour faire marche votre toolchain de CI avec, j’ai essayé, et croyez moi c’est relou.

Maintenant, j’aime que le packaging avance. J’aime même les nouveaux outils comme poetry. Mais la suite n’est pas ineluctable, et on peut concilier modernité avec sanité.

Programmation par contrat avec assert

Saturday 8 September 2018 à 21:40

Le mot clé assert est populaire en Python essentiellement grâce à la lib pytest, dont on vous a parlé dans le dossier sur les tests unitaires.

En dehors de ce cas d’usage, personne ne comprend bien son utilité.

Déjà, dans les tutoriaux, on vous signale de ne pas l’utiliser pour faire des vérifications importantes, à cause d’une particularité d’assert: il peut disparaitre à tout moment !

En effet, si vous lancez Python toutes voiles dehors avec l’option -o (pour “optimize”), les lignes contenant ce mot clé sont ignorées.

Alors, mille millions de mille sabords, pourquoi se faire chier à avoir ajouté ce truc ?

A quoi un machin qui peut disparaitre à tout instant peut-il bien servir ?

Well, it’s not a bug, it’s a feature, my dear.

Voyez-vous, on connait souvent le premier effet kisskool d’assert:

    assert condition

Et si la condition est fausse, on se tape une exception AssertionError.

En revanche, ce que les gens savent moins, c’est qu’il existe une seconde forme, beaucoup plus utile:

    assert condition, "Message en cas d'erreur"

Qui fait tout pareil, mais permet de donner un feedback a qui tombe sur l’erreur susnommée.

Et c’est là que c’est intéressant: parce que ça vous permet de mettre des vérifications complexes dans le code, qui vont permettre aux devs d’éviter les âneries. C’est ce qu’on appelle un contrat.

Imaginez une fonction qui prend en paramètre une valeur, qui est la clé d’un dictionnaire:

    ARTIBUSES = {
        'truc': 1,
        'bidule': 1,
        'machin': '2',
        'chose': '3',
        'chouette': '3',
        'foo': '4',
        # ...
    }
    
    def souquer_les_artibuses(artibuse):
    
        target = ARTIBUSES[artibuse]
        # un code de souquage professionnel s'ensuit

Si quelqu’un utilise votre code, et insère la mauvaise artibuse (le vil flibustier !), notre fonction va (s’)échouer sur une KeyError. Ceci va obliger le contrevenant (le perfide faquin !) à regarder dans le code source et comprendre le code pour trouver la source de son désarroi. Quelle perte de temps pour notre dev (le fils de pute !).

Une solution est alors de mettre:

    def souquer_les_artibuses(artibuse):
        if artibuse not in ARTIBUSES:
            raise ValueError(
                f"'{artibuse}'' n'est pas une artibuse valide. "
                f"Utilisez une valeur parmi: {', '.join(ARTIBUSES)}"
            )
        target = ARTIBUSES[artibuse]

Et c’est certes une bonne solution, claire et explicite.

Mais elle a un défaut majeur: à chaque appel, on rajoute le poids d’un test qui n’a aucun intérêt pour le fonctionnement normal du programme. En fait, la majorité des appels de cette fonction se feront avec les bonnes valeurs (logique sinon le code planterait), et donc notre test est un poids superflu.

Ce problème se cumule quand les tests deviennent plus nombreux, plus complexes, et plus lourds, tandis que la fonction est appelée de plus en plus de fois.

Comment concilier donc son besoin impérieux d’aider son prochain, qui est probablement soi-même un vendredi à 3h du mat après un push qu’on n’aurait pas du faire en fin de semaine, et éviter ce gâchis de ressource ?

Ventre-saint-gris de sa race ! Avec assert bien entendu !


    def souquer_les_artibuses(artibuse):

        assert artibuse in ARTIBUSES, (
            f"'{artibuse}'' n'est pas une artibuse valide. "
            f"Utilisez une valeur parmi: {', '.join(ARTIBUSES)}}"
        )

        target = ARTIBUSES[artibuse]

En dev, ou quand on debug en production, on obtient toutes les vérifications et infos nécessaires. Le contrat à remplir avec notre fonction est vérifié. On peut mettre autant de clauses à notre contrat qu’on le souhaite, aussi lourdes qu’on veut !

Quand on est prêt à relancer la prod en mode propre, on exécute tout avec -o

Les vérifications faites en amont d’une fonction sont ce qu’on appelle des pré-conditions dans le jargon de la programmation par contrat. Ce sont les plus faciles à comprendre et les plus courantes. On peut néanmoins faire également des vérifications à la fin de la fonction, qui permette de vérifier qu’on est bien dans un état cohérent à la sortie de celle-ci.

C’est ce qu’on appelle des post-conditions: c’est moins courant, et moins facile à écrire, mais très puissant car on se souci d’un état final (est-ce que mon résultat est > 3 ?), et non de comment on y arrive. Un moyen bien plus souple d’attraper des erreurs plutôt que de chercher toutes les combinaisons de ce qu’on peut mal faire.

Effets secondaires de -o

Le saviez-vous ? Python vient aussi avec une variable magique, __debug__, qui est à True par défaut. Utiliser -o met cette variable a False. Plus fort encore, toute condition sur __debug__ sera retirée du code !

if __debug__:
    un_dump_log_de_porc()

Pouf, avec -o, plus de dump.

Il existe même -oo pour retirer en plus les docstrings, et économiser un peu de mémoire.

Le problème avec assert

Le problème avec assert, c’est vous. Enfin je dis vous, le vous du passé, celui qui ne savait pas. En effet, plein de devs vont utiliser des assert dans leur code sans penser à mal. Et vous arrivez avec votre -o, et boom, le code est tout cassé. C’est bien con de ne pas pouvoir stripper ses assert à soi sous prétexte qu’une dépendance est codée par un connard Bachi-bouzouk.

Or assert est très souple, et permet de tester littéralement n’importe quoi. Du coup, cela demande un peu d’expérience pour savoir quand l’utiliser, et quand ne pas le faire.

Le concept général est: si votre erreur concerne la fonctionnalité fondamentale de votre fonction, levez toujours une exception. Si en revanche vous testez si les valeurs des paramètres correspondent à quelque chose de sain, et qu’une erreur n’aurait pas d’effet de bord, vous pouvez (ce n’est pas du tout obligatoire, une exception normale reste un usage correct) utiliser assert.

Donc, n’utilisez pas assert pour tester la logique de votre programme, ni pour protéger l’intégrité de vos données face à une erreur.

Une dernière chose: n’utilisez pas assert pour fournir un contrat basé sur les types (comme par exemple, appeler isinstance()), puisque mypy et les types hints le font déjà et qu’ils sont maintenant très agréables à utiliser.

Sam ne répondra plus 2

Tuesday 4 September 2018 à 03:18

Si vous nous avez écrit un email, vous savez qu’on a tendance a être lents pour répondre. En fait, parfois plus d’un an :)

Mais que ce soit sur twitter, reddit, indexerror, mastodon, les commentaires du blog ou par email, on finit par répondre à tout le monde. Les ratés existent, mais ils sont rares. La seule catastrophe étant notre bug tracker, parce que j’en fais suffisamment au boulot pour ne pas avoir le courage de le faire sur mon temps libre.

Gérer toute cette communauté, ça a un coût. J’y ai joyeusement participé pendant toutes ces années, parce que j’aime profondément aider les gens.

Notez que je ne me prends pas pour mère Thérésa, à moins qu’elle ai déjà fait du SM et vendu du viagra illégalement. Mais donner un coup de main a toujours été quelque chose d’important pour moi.

C’est la raison pour laquelle j’aime donner des formations. Parfois gratuitement. Parfois dans le cadre associatif.

C’est la raison pour laquelle je me déplace à des confs bien loin pour donner des talks même si personne ne sait que c’est moi. Parfois je discute avec un groupe de gens enthousiastes de ce super site NSFW. C’est vrai qu’il est bien. Vous l’avez connu comment ?

C’est la raison de la qualité des articles du blog également. Je passe un temps déraisonnable à me demander comment je vais pouvoir aider au mieux le lecteur avec une explication. Il m’est arrivé plusieurs fois de passer une journée entière sur un seul article compliqué, aux dépens d’un client que j’aurais pu facturer. Si on devait chiffrer le coût de ce site, je pense que ça me paierait un joli tour du monde.

Alors oui, ça a un prix, et je l’ai payé avec plaisir. Mes amis, qui m’ont entendu cracher sur les réseaux sociaux, ont même été étonnés de voir mon investissement sur Hacker news ou Twitter, au fil des années.

En cette fin 2018, je vais changer mon implication. J’ai envie de récupérer du temps libre, diminuer la tentation des interruptions et renforcer ma capacité d’attention, ce qui veut dire trancher dans le gras des distractions. Moins de surf sans but, moins de streaming, et moins de présence en ligne.

J’ai pensé à arrêter complètement le blog, mais soyons honnête, je n’écris plus au dixième du rythme de ses débuts, donc ça ne me prend pas si longtemps. Et un article de temps en temps, c’est thérapeutique. Je pense que j’ai besoin de mon troll JavaScript annuel pour des raisons de santé.

Ce qui me prend du temps par contre, c’est tout ce qui est autour des articles.

Donc, à partir de cette semaine, je vais arrêter de répondre sur Twitter, le subreddit (qui n’a de toute façon jamais pris) et indexerror. Twitter en particulier sera donc de nouveau en sens unique, comme à nos touts débuts: je poste, et je ne réponds pas.

Pour les commentaires du blog, j’ai fermé la création de compte, et j’ai autorisé les commentaires uniquement à ceux qui avaient déjà un compte. Je ne répondrai pas pour autant, et je sais que la communauté existante ne foutra pas le bordel, tout en leur permettant de glisser les corrections des mes coquilles débiles.

Pour mastodon, je vais fermer le compte complètement. Enfin le passer en privé et l’oublier car framapiaf ne permet pas la supression. L’expérience est réussie, je pense que c’est une bonne plateforme, mais le ratio taff/retour est trop bas pour mes nouveaux objectifs.

Quant aux mails, pour le moment je garde le canal ouvert. Ce qui devrait me permettre du coup de répondre beaucoup, beaucoup plus rapidement.

Je vous aime quand même, hein.

La débâcle de async en 3.7 27

Tuesday 7 August 2018 à 15:14

Quand les nouveaux mots clés async et await ont été introduits en Python 3.5, tout le monde a trouvé l’idée formidable. D’ailleurs, ça a été intégré à JavaScript.

Malheureusement, introduire des mots clés dans un langage est une opération très délicate.

Limites et contournements des mots clés

En Python les mots clés ont une caractéristique importante : on ne peut pas les utiliser pour quoi que ce soit d’autre.

Par exemple, class est un mot clé, donc je ne peux pas créer une variable, un attribut, ou une fonction appelé class. Ceci lève une erreur:

>>> class = 1
  File "", line 1
    class = 1
          ^
SyntaxError: invalid syntax
>>> class Foo: pass
... 
>>> Foo.class = 1
  File "", line 1
    Foo.class = 1
            ^
SyntaxError: invalid syntax
>>> 

Pour cette raison, quand on veut qu’une variable contienne une classe en Python, on la nomme cls:

>>> class Bar:
...     @classmethod
...     def wololo(cls):
...         print(cls, 'wololo')
... 
>>> 
>>> Bar.wololo()
 wololo
>>> 

C’est aussi pour cela que vous voyez parfois des variables nommées truc_. Souvent from_ par exemple, parce que from est un mot clé.

(pro tip: plutôt que from et to, utilisez src et dest)

Quand en Python 2 on a introduit True et False, un gros problème s’ensuivit: soit on en faisait des mots clés, et on pétait tout le code précédent qui utilisait ces mots, soit on en faisait des variables globales.

Le choix a été de garder la stabilité jusqu’à la prochaine version majeure, et c’est pour cela que:

Pour la 3.5, on avait donc ce même problème, avec une cerise sur le gâteau: la lib standard utilisait elle-même la fonction asyncio.async.

Le choix a donc de faire de async / await des variables globales, et de les transformer en mot clé en 3.7.

En 3.6, un warning a été ajouté pour rappeler aux gens de migrer leur code.

C’est un sacré taf, et ça comporte des risques comme nous allons le voir plus loin. C’est pour cette raison que l’ajout d’un mot clé dans Python est une des choses les plus difficiles à faire passer sur la mailling list python-idea.

Arrive la 3.7

La 3.7 est sortie avec tout un tas de goodies. Youpi. Mais aussi avec le passage de async/await de variables globales à mots clés, cassant la compatibilité ascendante. Quelque chose de rare en Python, et que personnellement j’aurais réservé pour Python 4, ne serait-ce que pour respecter semver.

Le résultat, tout un tas de systèmes ont pété: des linux en rolling release, des gens qui ont fait l’update de Python à la main, des gens qui maintiennent des libs compatibles 3.5 a 3.7…

D’autant que la 3.5 a asyncio.async, mais 3.7 considère ça une erreur.

Petit exemple avec l’impact sur debian.

Comment on aurait pu éviter ce merdier ?

D’abord, il aurait fallu ne pas introduire asyncio à l’arrache. Dans mon “au revoir” à Guido, je disais que je trouvais que les dernières fonctionnalités majeures de Python avaient été mises en oeuvre de manière précipitée.

Cela se vérifie encore et encore avec asyncio, dont il faudra que je fasse un article pour dire tout ce qui a mal tourné.

Casser la compatibilité ascendante dans une version mineure n’est pas acceptable, même si les dégâts sont limités et qu’on y survivra très bien.

Le fait qu’asyncio soit une API marquée comme “provisional” n’a jamais empêché quelqu’un d’appeler ses variables async. Après tout on utilise les threads depuis bien longtemps.

L’autre problème vient de l’amateurisme qui se glisse de plus en plus dans le dev.

C’est une bonne chose, parce que ça veut dire que la programmation est de plus en plus accessible et accueille de plus en plus de monde.

Mais cela veut dire aussi qu’une grosse part la population de programmeurs est aujourd’hui constituée de personnes qui n’ont ni les connaissances, compétences ou ressources pour faire les choses correctement.

On le voit particulièrement dans le monde JavaScript, ou c’est l’explosion (là encore, ça mérite un nouvel article). Mais l’exemple de la 3.7 nous montre que la communauté Python n’est pas immunisée, et je pense que le problème va s’amplifier.

Que veux-je dire par là ?

Et bien il y a 30 ans, cela ne serait pas venu à l’esprit de la plupart des devs de compiler quelques choses sans mettre les flags en mode parano pour voir ce qui allait péter. Après tout, quand on code en C, on sait que tout peut imploser à tout moment, alors la prudence est une question de culture.

Aujourd’hui par contre, la majorité des devs des langages haut niveau écrivent du code, font quelques tests à la main, et publient ça. D’autres les utilisent. Font des mises à jour en masse. Aucun ne prennent le temps ne serait-ce que d’activer les warnings les plus basiques.

Comme tout est facile à première vue, et c’est quelque chose dont on fait la promotion pédagogiquement parlant, car ça incite les gens à se lancer, on oublie la complexité inhérente à la programmation.

Mais il y a une différence colossale entre avoir un code qui marche une fois sur sa machine, et un code prêt pour la production.

Par exemple en Python, vous pouvez demander l’activation des warning pour chaque appel avec:

python -Wd

En 3.6, ça implique ceci:

>>> def async():
...     pass
... 
:1: DeprecationWarning: 'async' and 'await' will become reserved keywords in Python 3.7

L’info a toujours été là. Prête à être utilisée.

Mais alors pourquoi ne pas afficher tous les warnings, tout le temps ?

Et bien si je le fais:

python -Wa

Voilà ce que ça donne quand je lance juste le shell de python 3.6:

Voir le code sur 0bin.

Vous comprenez donc bien que ce n’est PAS activé par défaut. En fait, originalement le message était dans le corps de l’article, mais j’ai du le mettre sur 0bin parce que ça faisait planter WordPress. Si.

A chaque upgrade, il est important de vérifier les warnings pour préparer ses migrations futures.

Oui, c’est du boulot.

En fait…

La programmation, c’est BEAUCOUP de boulot

Même si on arrive maintenant à extraire une frame vidéo en gif en une ligne de commande.

Surtout maintenant qu’on y arrive en fait, car on multiplie les agencements hétérogènes de boites noires pour créer nos merveilleux programmes qui font le café.

Alors on prend des raccourcis.

Et puis aussi, parce qu’on ne sait pas. Qui parmi les lecteurs du blog, pourtant du coup appartenant à la toute petite bulle des gens très intéressés par la technique, connaissaient le rôle des warnings et comment les activer ?

Mais ce n’est pas le seul problème. Il y a clairement une question d’attentes et de moyen.

L’utilisateur (ou le client) final veut toujours plus, pour moins cher, et plus vite !

Et le programmeur veut se faire chier le moins possible.

Comme la complexité des empilements d’abstractions augmente, cela conduit à ignorer ce sur quoi on se base pour créer ce qui doit combler notre satisfaction immédiate.

J’ai parlé d’amateurs plus haut.

Mais je ne parle pas simplement de mes élèves. De mes lecteurs.

Je parle aussi de moi.

Prenez 0bin par exemple.

Il n’est plus à jour. Il n’a pas de tests unitaires. Il a des bugs ouverts depuis des années.

Ce n’est pas pro du tout.

Sauf que je ne suis pas payé pour m’en occuper, et c’est bien une partie du problème: nous sommes de nombreux bénévoles à faire tourner la machine a produire du logiciel aujourd’hui. Donc si je n’ai pas envie, fuck it !

Vous imaginez si l’industrie du bâtiment ou celle de l’automobile tournaient sur les mêmes principes ?

La moitié des dessins industriels faits par des bloggers, des étudiants, des retraités, des profs de lycées, des géographes, de biologistes et des postes administratifs ?

Des immeubles et des voitures dont des pièces sont fabriquées par des potes qui chattent sur IRC et s’en occupent quand ils ont le temps ? Gratuitement. Y compris le service après-vente.

Alors que les usagers veulent toujours plus: des normes sismiques et de la conduite autonome. Tout le monde le fait, alors la maison de campagne et la fiat punto, c’est mort, personne ne l’utilisera.

Difficile de maintenir la qualité à cette échelle.

Il y a tellement de demandes de dev, jamais assez d’offres, de ressources toujours limitées.

Et ça grossit. Ça grossit !

Aides techniques

Ceci dit, à l’échelle de la PSF, ça aurait dû être évité.

Avant d’aborder les aides techniques, il serait bon d’arrêter les conneries. Je me répète, mais c’était une vaste dauberie de faire passer async/await en mot clé avant Python 4.

J’ai parfaitement conscience du besoin de faire progresser un langage pour ne pas rester coincé dans le passé. Je suis pour async/await, très bonne idée, superbe ajout. Mettre un warning ? Parfait ! Mais on respecte semver s’il vous plait. Si vous avez envie de faciliter la transition, mettre un import __future__, et inciter les linters à faire leur taff.

En attendant, pour la suite, Python va faciliter le debuggage.

Par exemple, depuis la 3.7, les DeprecationWarning sont activés par défaut au moins dans le module __main__. Donc un développeur verra ses conneries bien plus rapidement.

E.G:

Imp est déprécié en 3.6, mais sans -Wd, on ne le voit pas:

$ python3.6
Python 3.6.5 (default, May  3 2018, 10:08:28) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import imp

En 3.7, plein de modules importent imp, mais les DeprecationWarning ne sont pas montrés, car ça arrive dans des codes importés. En revanche, si dans le module principal, vous importez imp:

$ python3.7 
Python 3.7.0+ (default, Jun 28 2018, 14:08:14) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import imp
__main__:1: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses

Ça donne une info importante, sans foutre un mur de warnings à chaque lancement.

Une autre aide est l’apparition, toujours en 3.7, du mode développement de Python avec -X dev qui active tout un tas de comportements aidant au développement:

Évidemment, tout ça ne sert pas à grand-chose si on ne sait pas ce qu’il faut en faire. Et ça demande du temps et du travail, ce que l’amateurisme ne permet pas forcément.

Enfin je dis ça. La plupart des employeurs s’attendent à tout, tout de suite également. Donc au final, n’est-ce pas la culture générale de notre industrie qui est en train de virer dangereusement vers le vite fait mal fait ?

Même si il y a clairement une question de compétence (un prof de maths est généralement compétent en maths, alors que j’attends toujours de rencontrer un prof d’info qui est capable de mettre quelque chose en prod), la pression du marché a créé des attentes impossibles…

L’informatique n’existe comme secteur économique que depuis quelques décennies, contre des siècles pour la plupart des autres disciplines scientifiques. Pourtant on exige d’elle le même niveau de productivité. Il a bien fallut rogner quelque part, et c’est la fiabilité qu’on a choisit.

Quand il y 20 ans, on rigolait en comparant le debuggage de Windows a la réparation d’une voiture, et la punchline sur le redémarrage, ce n’était pas grave: un peu de virtuel dans un monde plein d’encyclopédies papier, de cabines ou bottins téléphoniques et autres cartes routières.

Aujourd’hui que notre monde entier dépend du fonctionnement de nos conneries codées à l’arrache, c’est plus emmerdant. Et ça explique aussi pourquoi le téléphone de ma grand mère fonctionne toujours mieux pour faire des appels que mon putain de smartphone a 600 euros. Mais je peux draguer une meuf par texto en faisant caca à l’aéroport. Tout a un prix.

Guido van Rossum s’offre “des vacances permanentes” 19

Thursday 12 July 2018 à 22:56

Le BDFL (Dictateur Bénévole Bienveillant À Vie) et créateur du langage Python vient d’annoncer qu’il laissait son bébé à la communauté.

Sans quitter son rôle de core dev, et en suggérant qu’il passe plus de temps en tant que mentor de ses collègues sur le projet, il abandonne néanmoins son pouvoir de décision absolu sur le langage et son rôle de validateur ultime de chaque introduction de nouvelles fonctionnalités.

Dans son email, il ne passe pas le pouvoir à qui que ce soit ni n’invite à un mode de direction particulier. Il suggère que l’équipe actuelle des core devs, les développeurs ayant les droits de commit sur le repository du langage, choisisse le format qui leur convienne le mieux pour diriger à présent le projet.

Un moment important dans la vie de Python, mais aussi un événement qui demande beaucoup de remise en contexte.

Python-idea, Python-dev et les PEP

Durant les dernières années, les décisions de modification du langage passaient généralement par plusieurs phases.

D’abord, la proposition faite sur la mailing list python-idea. Cette liste est publique. Tout le monde peut y participer et y donner son avis.

Après débat, si le climat n’est pas hostile (ce qui est une notion TRES subjective), un des core devs suggère généralement à l’auteur de l’idée d’écrire un PEP.

Le PEP (Proposition d’Amélioration de Python) est l’équivalent d’une RFC pour Python. C’est un document formalisant une proposition d’amélioration du langage et de son écosystème. Le plus connu est bien entendu le PEP 8.

S’ensuit encore plus de débats, et des modifications itératives du PEP, jusqu’à, soit l’abandon du projet par l’auteur, soit l’oubli, soit le verdict de Guido.

Ce dernier est définitif: le PEP est approuvé ou rejeté. Dans le premier cas, il sera appliqué. Dans le second, il part à la poubelle.

Quelque part à la fin de ce processus, les implémenteurs du PEP discutent en plus petit comité, sur la liste python-dev, de la réalisation.

Guido a toujours, jusqu’ici, été donc la dernière étape de filtre de cet enchaînement. A la foi gardien de sa philosophie du langage, et goulot d’étranglement.

Il y a eu quelques améliorations, comme la nomination ponctuelle de BDFL délégués pour certains sujets, mais le format reste quand même globalement le même.

Pride and prejudice

Ce système a l’avantage d’être très ouvert. Tout le monde peut participer. Peu de personnes le font pourtant, par rapport à la masse d’utilisateurs de Python, mais c’est déjà beaucoup si on considère l’inertie que ça implique.

Le mail est un format très accessible, décentralisé, ouvert et standard. Son austérité évite l’effet réseau social qu’on voit trop souvent sur les outils plus modernes.

En contrepartie, le processus est très flou. Il n’y a pas de vote a proprement parler. Les threads s’enchaînent un peu n’importe comment. Les nouveaux venus ne sachant pas comment utiliser l’outil le font imparfaitement. Et le media ne permet pas facilement de suivre la continuité à court terme et à long terme de grand-chose, ni en termes de flux, ni en termes de référence, ni en termes de recherche.

Mais c’est aussi l’aspect social qui est problématique. Il n’y a aucune organisation claire dans la liste, et tout le monde semble “au même niveau”. Or ce n’est pas absolument pas le cas. La réputation et les participations passées, ainsi que les caractères des participants et leurs relations jouent énormément sur le processus. Le timing également.

Ça parait équitable sur le papier, mais c’est une illusion, et en prime cela implique des frictions qui pourraient être évitées. Par exemple quand un étudiant demande à Larry Hastings de l’aider à faire ses devoirs ou qu’un auteur de PEP cite le Zen of Python à Tim Peters. Inversement, quand vous proposez une idée, et que tout le monde vous envoie péter, mais que 6 mois plus tard, Brett Cannon dit que c’est intéressant et que tout le monde crie au génie, ça fout les boules.

Ajouté à cela, la qualité du débat qui peut varier du tout au tout : du caprice à la revue technique, en passant par le mail à côté de la plaque, la crise d’égo, l’appel au calme, le récap qui aide tout le monde, les idées brillantes, les suggestions étonnantes, les redites, et le spam.

Et évidement, la réponse par défaut est toujours non.

Se faire entendre là dedans est très difficile. Garder son calme l’est souvent aussi. Mais surtout, persévérer à travers le processus durant le temps nécessaire pour l’aboutissement de celui-ci est une épreuve épuisante, irritante, et ingrate. Surtout quand 9 fois sur 10, elle se finit par un rejet.

Un rejet cependant, n’est pas la mise à mort d’une idée. L’année suivante on peut relancer le débat, et ainsi de suite, comme un politicien à l’assemblée qui veut faire passer son projet de loi. Et comme au Parlement, la même idée présentée par une nouvelle personne, ou avec un autre timing peut avoir un résultat radicalement différent.

Un anus pour les rassembler tôt

GvR, bien qu’au sommet de cette pyramide, n’est pas isolé de tout cela, bien au contraire. Il est une des rares personnes qui doit trancher sur presque tout, et donc se coltiner une bonne partie des débats. Et des réactions quand il rejette l’idée d’autrui.

À ceci se rajoute sa présence sur les bugs trackers, et bien entendu son activité de développeur.

Un rôle difficile, fatigant, et un vrai sacerdoce pour quelqu’un qui pourrait dire “allez tous vous faire foutre, j’ai pondu ce langage utilisé par des millions de personnes tout seul, je sais mieux que vous” au lieu de prendre en considération l’avis du public.

Un rôle, je vous le rappelle, qu’il tient depuis plus de 20 ans.

Depuis la 3.4, on sent le poids commencer à peser sur ses épaules. A 62 ans, et toujours avec un travail à plein temps chez Dropbox (qui heureusement lui laisse le loisir de travailler sur Python), on peut imaginer l’énergie nécessaire pour s’impliquer encore autant.

Cela se ressent particulièrement dans ses mails et ses tickets. Une sorte de lassitude. Et une retenue qu’on devine de plus en plus difficile.

Honnêtement, je ne sais pas comment il a fait pour ne pas exploser sur quelqu’un. Dans certains échanges que j’ai eus avec lui sur la liste ou sur github, si nos rôles avaient été inversés, j’aurais sans aucun doute été bien moins diplomate.

sys.exit() maintenant, avant que la charge ne devienne trop pesante, est à mon sens un acte de grande classe.

Comme un comédien, un musicien, un metteur en scène ou un écrivain qui fait ses adieux au sommet de son art. J’aurais aimé que Lucas, Spielberg et Besson aient su en faire autant.

Mais pour bien comprendre à quel point cette décision de laisser sa place demande du courage, il faut réaliser une chose: il laisse son enfant dans les mains des autres. L’œuvre de sa vie. Une réalisation colossale qui plus est, qui a généré des centaines de milliers d’emplois, fait tourner des milliers de projets.

Moi, j’ai du mal à m’imaginer arrêter d’écrire ce misérable petit blog. Et pourtant j’y ai pensé souvent.

L’étincelle qui a fait déborder la moutarde, c’est bien entendu le débat sans fin sur l’expression d’assignation, et la critique vigoureuse de son acceptation. (C’est vrai que c’était chaud)

Guido en a eu ras le cul, quoi.

So what now ?

Personnellement, j’accueille la nouvelle avec un mélange d’espoir et de mélancolie.

Python n’aurait jamais été ce qu’il est aujourd’hui sans la constante vigilance de son BDFL.

Dire “non” est la partie la plus importante pour sculpter une expérience. C’est ce qui fait la différence entre Gates et Jobs, Van dam et Lee, Hitler et… heu… non.

C’est ce qui fait qu’on n’a des lambda bridées et pas d’opérateur pour ajouter un élément dans une liste. Qu’on le veuille ou pas.

Et c’est ce qui fait qu’un langage né en fucking 1985 (avant Java !) tient toujours la route aujourd’hui. A gardé sa lisibilité. Sa facilité de prise en main. Et continue d’être utile.

C’est un travail de titan !

Néanmoins je ne peux m’empêcher de noter que les dernières fonctionnalités majeures de Python ont été introduites de manière brouillonne. Je pense notamment au type hints et à asyncio, que Guido a bdfl -f sans donner le temps de mûrir leur design. Elles ont mis plusieurs versions à ne serait-ce qu’être utilisables, et méritent encore du travail.

Je pense aussi que Python est prêt pour des ajustements, et espère que passer le flambeau à l’équipe de core dev va apporter du renouveau au langage.

En effet, il est peu probable qu’un nouveau BDFL s’installe, et bien qu’il soit trop tôt pour faire une prédiction, la mise en place d’un quorum semble plus probable. Dans ce cas, il faudra sans doute un vecteur de vote. Et de là, qui sait, naîtra peut-être un complément ou replacement à python-idea.

Je l’espère en tout cas.

Sortir de l’usage de la mailing list pour un outil plus encadré, mettant les propositions en avant, avec un système de sondage, des procédures plus claires, des références plus faciles au passé, et une distinction explicite du statut des personnes qui s’expriment.

Bref, faciliter l’accès au processus, tout en permettant une gestion plus saine. On ne voudrait pas que Victor ou Yuri nous posent leur dem dans les 6 mois pour cause de pétage-de-cablite aigue.

Également, qui sait, peut-être reviendra-t-on – pour le meilleur ou pour le pire ? – sur des BanDFL tel que:

Difficile de croire que le débat ne sera pas relancé maintenant que Cerbère ne garde plus les Champs Élysées.

Évidemment, il est logique qu’il y ait un temps de flottement. D’abord par respect pour le père de Python. Ça ferait un peu GoT d’enchaîner quand même. Ensuite parce qu’il va falloir qu’un nouveau mode de fonctionnement émerge, et prouve son efficacité.

Quoi qu’il arrive

Merci à Guido Van Rossum pour ce cadeau immense.

On va essayer de ne pas trop l’abîmer.