PROJET AUTOBLOG


Sam & Max: Python, Django, Git et du cul

Site original : Sam & Max: Python, Django, Git et du cul

⇐ retour index

Je n’expliquerai plus les CBV 17

lundi 11 mai 2015 à 13:42

Les Class Based Views sont des vues génériques réutilisables qui permettent de faire automatiquement des tâches courantes dans Django comme :

Je ne les ai jamais aimées. Avant, les vues génériques étaient sous forme de fonction, simples, pratiques, c’était parfait. Et ça a été retiré du framework pour des versions OO sous prétexte que c’était plus flexible.

Maintenant, ce sont ces gros tas immondes, avec un ordre d’appel de méthodes complexes, des mixins dans tous les sens et une chaine d’héritage velue.

Je pense que c’est une bonne occasion pour rappeler que la POO n’est pas faite pour être utilisée partout, tout le temps. Aucun putain de paradigme de programmation n’est fait pour être utilisé partout, tout le temps. C’est pour ça qu’il y en a plusieurs.

Dans notre cas des CBV, la conséquence est que c’est un enfer pour expliquer tout usage qui ne soit pas un hello world, ce que la doc se garde bien de faire.

Après il y a toujours un malin pour dire “mais si tu vois tu fais ça, et ça, ça prend 5 lignes, c’est pas si dur”. Ouai, maintenant va expliquer ça à un stagiaire, et donne lui un exercice avec une form view qui doit modifier un objet, le lier à un user seulement si il a la permission de le faire. Juste pour voir en combien de temps il trouve. Je vais en WE à Barcelone en attendant. Je prévoie une extension à Rome pour quand il devra relire son code le trimestre prochain.

Et si encore c’était pour un gain de productivité évident, je fermerais les yeux. Mais c’est pas le cas. Même moi qui sait utiliser ces… ces choses… je dois regarder dans la doc à chaque fois que j’en utilise une. Et ensuite quand je relis mon code quelques mois plus tard, je chope de pattes d’oies aux coins des yeux.

If you have to refer to the documentation every time you use a module, find (or build) a new module.

Dixit Kenneth Reitz, le mec qui a pondu requests. Donc on va user something else que les CBV, si vous le voulez bien.

Un lecteur m’a (encore) pointé du doigt qu’un schéma du MRO et de l’ordre d’appel des méthodes serait utile. Vous vous rendez compte du truc ? On peut comprendre l’ORM sans schéma alors que c’est une machine de guerre, et il faut une carte pour comprendre comment faire un listing un peu custo avec une CBV ? J’ai évalué la somme de travail pour faire ledit schéma, et elle est énorme : trop de classes, trop de méthodes, trop de subtilités.

Bref, je jette le tablier, fuck les CBV. Je ne les inclurai plus dans mes formations, mes tutos, mes aides sur les forums, etc.

Zerobin passe à Python 3 16

dimanche 10 mai 2015 à 20:19

Ça faisait longtemps que je n’avais pas touché 0bin, le pastebin chiffré côté client écrit en Python.

Le support de Python 2 devait s’arrêter en mai 2015, soit ce mois-ci. Cela a été repoussé à 2020, mais pour marquer le coup symboliquement j’ai porté notre brave bestiole qui supporte maintenant la 2.7 et la 3.4.

Comme je n’ai jamais pris le temps de faire des tests unitaires sur ce projet, il est possible que j’ai cassé des trucs. J’ai testé manuellement, mais bon, on ne sait jamais, je vous avertis avant du danger :)

Le portage a pris une après-midi.

Même si ce n’est pas l’affaire de deux minutes, ce n’est pas non plus la montagne qu’on s’en fait. C’est du boulot, chiant et ingrat (surtout pour supporter 2.x ET 3.x avec une seule base de code), mais pas un travail de titan.

Et en prime, ça me permet de faire un peu reparler du projet qui n’avait plus eu de mise à jour depuis un bail.

Il mérite d’ailleurs encore pas mal d’amour :

Bref, ce “petit” projet a de beaux jours devant lui. Sauf que pour l’instant, y a une seule limace qui code dessus.

P.S : j’ai aussi réparé le “Mail this”, qui n’utilise plus l’URL raccourcie. En effet cette dernière n’est pas dispo dès qu’on dépasse le rate de l’API google, ce qui arrive tous les jours maintenant. La rançon du succès je suppose.

Pendant ce temps, à Vera Cruz 8

dimanche 10 mai 2015 à 11:29

Pour une fois, ce n’est pas un article payé par Tavendo, mais bien un truc que je ponds par enthousiasme :)

Pendant qu’on en parle pas, la stack WAMP continue d’évoluer, des mises à jours significatives ayant été apportées à Crossbar.io, ainsi qu’aux libs Python et JS d’autobahn. Parmi les plus intéressantes :

Inutile de dire que c’est trop cool.

Pour profiter de tout ça, il suffit de faire :

pip install crossbar autobahn --upgrade

Et de télécharger la nouvelle version de la dernière version de la lib JS.

Licence MIT

Auparavant le travail de Tavendo était essentiellement sous Licence Apache. Une licence libre, certes, mais qui pouvait poser problème quand on mélangeait tout ça avec d’autres licences (par exemple, elle n’est pas compatible avec la GPL2). Avec la version 0.10, le code est maintenant sous licence MIT, beaucoup plus permissive.

Joker pour les subs

Supposez que vous faites un système de jeu d’échec donc chaque coup déclenche un événement “chess.game.[id_de_partie]”. C’est pratique, car seuls les clients intéressés à cette partie vont recevoir les événements. Mais si votre serveur doit enregistrer un log de tous les coups d’une partie, il faut que chaque client envoie AUSSI les coups au serveur explicitement.

C’était en tout cas vrai avant cette mise à jour, puisque maintenant on peut spécifier des jokers dans les noms des topics au moment de l’abonnement.

Essentiellement il y a deux modes.

Le mode “prefix”, qui match tous les events qui commencent par ce nom :

session.subscribe("debut.du.nom.du.topic", callback, { match: "prefix" });
# matchera debut.du.nom.du.topic.genial et debut.du.nom.du.topic.trop.cool

Et le mode “wildcard” qui permet, un peu comme les glob Unix (mais on utilise “..” au lieu de “*””), de faire un texte à trou :

session.subscribe("nom.du.topic..general", callback, { match: "wildcard" });
# matchera "nom.du.topic.moins.general" et "nom.du.topic.oui.mon.general"

Tous les callbacks qui matchent un topic seront appelés.

Plusieurs clients pour la même procédure

On peut utiliser le même principe que pour les sub avec joker, mais pour les procédures.

session.register("debut.du.nom.de.la.procedure", callback, { match: "prefix" });    
session.register("nom.de.la.procedure..generale", callback, { match: "wildcard" });

La différence avec le subscribe, c’est que seule UNE procédure est appelée. Dans les cas simples, un match exact prend le dessus sur un prefix (et le plus long prefix gagne toujours), qui prend le dessus sur un wildcard. Crossbar n’implemente pas encore de résolution pour deux wildcards en conflits, et je ne sais pas ce qu’il fait dans ce cas.

Il est aussi possible de de définir des règles d’appels en faisant :

session.register("nom.de.la.procedure..generale", procedure1, { invoke: "regle"});

La règle peut être :

“roundrobin” et “random” sont pratiques pour faire du load balancing.

“last” et “first” sont pratique pour les mises à jour d’un client sans arrêter le serveur. En gros on rajoute un client, on attend un peu, “last” route tout sur le dernier client, donc le nouveau client prend les requêtes, et on peut arrêter le vieux clients sans souci.

Meta RPC

Crossbar met automatiquement à notre disposition des procédures distantes toutes faites qui donnent des informations sur l’état des clients et du routeur. Voici les RPC que vous pouvez maintenant faire :

En gros, si vous voulez faire une admin qui vous permet de killer certains client ou rechercher si des events existent, vous utilisez ça.

Meta SUB

De même, le routeur envoie maintenant des publications sur des sujets concernant le cycle son cycle de vie et celui des clients. On peut donc s’abonner à ces meta topic pour réagir à l’activité de son système :

Ce genre de truc est idéal pour faire un petit outil de monitoring pour son archi et voir ce qui se passe en temps réel.

Le HTTP bridge est complet

Le bridge HTTP propose maintenant PUB/SUB, et tout RPC. On peut donc maintenant utiliser crossbar depuis n’importe quel app qui peut faire du HTTP : flask, pyramid, ruby on rails, du PHP pur, wget en ligne de commande et tout le bordel. C’est plus verbeux, mais ça dépanne bien.

Quels exercices pour débutants en Python ? 40

mercredi 6 mai 2015 à 20:51

Quand quelqu’un commence à programmer avec Python, il faut lui apprendre les bases : les conditions, les boucles, les listes, les dicos, les fichiers, les fonctions, les classes et tout le bordel.

Pour que ça rentre, et pour identifier les points à consolider, les exercices sont indispensables.

Malheureusement un bon exercice est très dur à construire :

Il y a des grands classiques :

Certains ne sont plus possibles : parcourir l’API tweeter par exemple est devenu beaucoup trop compliqué alors qu’avant c’était un truc super fun à faire faire.

D’autres sont vachement plus faciles : s’envoyer un sms d’alerte si il va pleuvoir aujourd’hui est un jeu d’enfant si on est chez free qui a une URL pour ça.

Est-ce que vous avez des exos sympas à proposer ? Je cherche l’inspiration.

Si vous postez un exo, merci d’y joindre les notions testées et les pré-requis ainsi que, si nécessaire, le public visé.

Views VS generators 3

mercredi 25 mars 2015 à 19:57

Avec Python 2.7, un outil appelé les “views” (les “vues”) est apparu. Une vue est juste un enrobage qui permet de voir un objet d’une certaine façon, et de le manipuler d’une certaine façon (avec une autre API), sans changer cet objet.

Les vues ont surtout été notables pour leur apparition dans les dictionnaires avec Python 2.7:

    >>> scores = {"sam": 1, "max": 0}
    >>> scores.items() # retourne une lsite
    [('max', 0), ('sam', 1)]
    >>> scores.iteritems() # retourne un générateur
    <dictionary-itemiterator object at 0x7f8782a26628>
    >>> list(scores.iteritems()) # sans views
    [('max', 0), ('sam', 1)]
    >>> scores.viewsitems() # avec views
    Traceback (most recent call last):
      File "<ipython-input-12-dc0b08011047>", line 1, in <module>
        scores.viewsitems() # avec views
    AttributeError: 'dict' object has no attribute 'viewsitems'
 
    >>> scores.viewitems() # retourne une vue
    dict_items([('max', 0), ('sam', 1)])

Néanmoins personne ne les a vraiment utilisé, et c’est un tort. Elles sont en effet très performantes, et pour cette raison sont retournées par défaut avec items() en Python 3.

En effet, les vues ne sont qu’un enrobage : elles ne contiennent rien, et donc ne prennent pas beaucoup mémoire, tout comme les générateurs.

Mais contrairement aux générateurs, les vues ne se vident pas et peuvent exposer une API plus complète que les générateurs, comme par exemple déclarer une taille :

>>> items = scores.iteritems()
>>> list(items)
[('max', 0), ('sam', 1)]
>>> list(items) # woops
[]
>>> items = scores.viewitems()
>>> list(items)
[('max', 0), ('sam', 1)]
>>> list(items)
[('max', 0), ('sam', 1)]
>>> len(scores.iteritems()) # nope
Traceback (most recent call last):
  File "<ipython-input-21-9c7f250da51d>", line 1, in <module>
    len(scores.iteritems())
TypeError: object of type 'dictionary-itemiterator' has no len()
 
>>> len(scores.viewitems())
2

Alors certes, on ne peut pas mettre des vues partout, et les générateurs restent utiles. Mais quand il est possible de les utiliser, et à moins d’avoir besoin d’une liste afin de modifier les valeurs in place, il n’y pas de raison de ne pas le faire : c’est le meilleur des deux mondes.