PROJET AUTOBLOG


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

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

⇐ retour index

Le don du mois : nuitka 16

lundi 1 février 2016 à 17:37

Comme je vous l’ai dit dernièrement, le packaging et les performances sont deux points qui méritent d’être améliorés en Python.

Nuitka est un projet qui vise à tacler ces deux problèmes d’un coup en compilant le code Python pour obtenir un exécutable autonome sous forme de code machine.

Plus besoin de s’inquiéter d’avoir la bonne version de Python installée. Plus besoin de se soucier d’avoir Python, ou une lib quelconque installée. Et en prime, le compilateur implémente le plus d’optimisations qu’il peut.

Nuitka est un projet en cours et son équipe est petite. Les progrès sont sérieux, mais lents. Histoire d’encourager tout ça, je fais un don de 50€ à l’auteur.

Pour donner à votre tour, c’est par ici.

Nouvelle release de crossbar: historique des events et crypto 8

dimanche 31 janvier 2016 à 19:25

Je suis méga à la bourre. Entre les tickets github qui s’accumulent, les comments auxquels j’ai toujours pas répondu et la liste d’articles à écrire qui augmente au lieu de diminuer (mais comment, bordel, comment ?), j’ai vraiment du mal à suivre.

Je dois toujours un article sur Polymer + Crossbar à Tavendo. Et il faut que je fasse un tuto sur l’authentification également (en attendant, y a des exemples plus à jour).

Fichtre.

En attendant, je vais en profiter pour faire un article vite fait sur la dernière release, puisque Crossbar, le routeur WAMP, passe en 0.12.

Comme d’hab, correction de bugs, amélioration du support de Python 3, plus de docs et d’exemples, blablabla…

Mais ce qui est vraiment intéressant, c’est l’historique des évènements.

Normalement un évènement est éphémère, dans le sens où une fois qu’il a été propagé, vous ne pouvez plus le recevoir. Si vous arrivez après la fête, c’est terminé.

C’est un problème, par exemple si vous redémarrez un client qui a besoin de ces évènements. Ou si vous implémentez un client qui veut savoir ce qui vient de se passer avant de se pointer, comme dans le cas d’un chat : on veut avoir les derniers messages postés.

Par défaut, l’historique n’est pas activé, puisqu’il y un coût pour chaque pub/sub. On doit explicitement le demander pour chaque event dans le fichier de config :

{
   "name": "realm1",
   "roles": [
   ],
   "store": {
      "type": "memory", # ou stocker l'historique
      "event-history": [
         {
            "uri": "mon.uri.pour.un.event", # quel type event
            "limit": 10000 # combien d’events stocker
         }
      ]
   }
}

type n’accepte pour le moment que memory, qui est une simple liste en mémoire dans crossbar, et bouffe donc de la RAM. On perd aussi l’historique au redémarrage du routeur, mais ça a l’avantage d’être très rapide.

Pour la prochaine version, Tavendo va implémenter un stockage dans une base lmdb et si ils font une belle API, on peut s’attendre à voir fleurir des backends pour SQLAlchemy, Django, Redis, etc.

event-history prend un liste d’events (les URIs peuvent utiliser les jokers introduits dans la version précédente), on met la limite du nombre total d’events à stocker pour cet URI en particulier.

Pour profiter de l’historique côté client, il faut obligatoirement avoir un abonnement à un event dont les messages sont sauvegardés. On ne peut pas récupérer l’historique de messages auxquels on n’est pas abonnés : forcer l’abonnement oblige en effet le client à passer le check des permissions.

Par exemple, en JS, d’abord on s’inscrit:

var promise = session.subscribe('mon.uri.pour.un.event',
   function (args, kwargs, details) {
      // bon là vous faites bien ce que vous voulez avec les nouveaux events
      //, car ça n’a rien à voir avec l’historique
   }
)

Puis on demande les events:

promise = promise.then(function (sub) {
      // L’abonnement retourne un objet "subcription" qui possède l’id
      // dont on a besoin pour demander l’historique des events.
      // On fait un petit RPC sur la meta API 'wamp.subscription.get_events'
      // qui demande aux routeurs tous les X derniers events qui matchent
      // notre abo. Ici x = 10
      return session.call('wamp.subscription.get_events', [sub.id, 10]);
)

Et enfin, on a droit à l’histo:

promise.then(function (history) {
    console.log(history.length, " events:");
    history.forEach(function(event){
        console.log(event.timestamp, event.publication, event.args[0]);
    })
 });

En Python, le code pour récupérer l’histo est logiquement:

import asyncio
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner
 
 
class Component(ApplicationSession):
 
    async def onJoin(self, details):
 
 
        def on_event(i):
            print("Got: {}".format(i))
 
        # pareil on chope la souscription
        sub = await self.subscribe(on_event, u'mon.uri.pour.un.event')
        # et on demande la liste des 10 derniers events pour cet abo
        events = await self.call('wamp.subscription.get_events', sub.id, 10)
        # et on boucle. Et on kiff await parceque putain c’est pratique.
        for event in events:
            print(event['timestamp'], event['publication'], event['args'][0])
 
    def onDisconnect(self):
        asyncio.get_event_loop().stop()
 
 
if __name__ == '__main__':
    runner = ApplicationRunner("ws://127.0.0.1:8080/ws", 'realm1')
    runner.run(Component)

L’autre point phare de cette release, c’est la dépréciation de Mozilla Persona comme méthode d’authentification (le projet est dead) et la promotion de deux nouvelles méthodes: les certificats TLS et les paires de clés publiques/privées (Curve25519 pour le moment).

C’est une très bonne nouvelle, car ça veut dire plus de mots de passe dans les fichiers de configuration en production pour identifier vos propres clients qui ont forcément des privilèges supplémentaires.

Je reviendrais là dessus en faisant le tuto sur l’authentification.

Une release chouette donc. Mais qui introduit plein de dépendances à des extensions en C qui pourraient être optionnelles, ce qui rend l’installation plus compliquée. Je suis en train de discuter avec la team pour voir si on peut arranger ça, mais Tobias à l’air plutôt pour les garder. Si vous aussi vous voulez garder la simplicité de la base pure Python, rejoignez la discussion.

Enfin, on a pu voir l’annonce d’une feature très intéressante : le chiffrement end-to-end des messages WAMP. Ça, c’est chouette. C’est pas encore implémenté, mais ça veut dire que la prochaine release, vous pourrez probablement envoyer des messages à travers le serveur WAMP sans que celui-ci puisse les lire.

Evolution de Python 21

samedi 30 janvier 2016 à 21:31

La communauté Python est assez d’accord ces derniers temps. Maintenant que le plus gros de la débâcle Python2/3 est derrière nous (en attendant le contre coup des retardataires de 2020) et qu’on a un modèle d’IO async bien clean, les trucs qui fâchent sont assez clairement délimités:

Sur ces questions, du travail est activement en cours.

Pour le multi-core, Eric Snow propose un modèle propre qui permettra d’utiliser plusieurs interpréteurs en parallèle en partageant des valeurs sans avoir à les sérialiser.

Concernant l’amélioration des perfs, ce sera un taf plus long, mais:

Bref, y a du potentiel.

Pour le packaging, les wheels vont enfin arriver sous Linux, ce qui fait qu’on pourra bientôt pip installer des binaires sur les 3 OS majeurs. Peut-être même BSD qui sait.

Nuikta, le compilateur Python, supporte maintenant await/async. J’ai beaucoup d’attentes envers ce projet, ça mérite un don du mois :)

On est sur la bonne route.

L’année 2016 va être trop cool, et dans mon enthousiasme, je vais écrire à propos de choses que j’aimerais vraiment voir arriver dans Python.

try/except error inline

Beaucoup de codes en Python ressemblent à ça :

try:
    val = faire un truc
except MonErrorALaNoix:
    val = "valeur par default"

Par exemple :

try:
    val = stuff[index]
except (IndexError, TypeError):
    val = None

Ce sont des opérations si courantes qu’on a plein de raccourcis comme dict.get ou next(i, None). En effet, en Python try/except n’est pas juste un mécanisme de gestion d’erreur, c’est un mécanisme de contrôle de flux à part entière.

Car franchement, ça fait chier de se taper 4 lignes pour écrire ça. En effet, on a bien les expressions ternaires pour les if/else:

val = truc if bidule else machine

Et bien il existe un PEP (rejeté) qui propose ça:

val = faire un truc except MonErrorALaNoix: "valeur par default"

J’adore. C’est pratique, générique, propre.

Bien entendu ça peut être abusé, comme les expressions ternaires, pour faire de la merde illisible. Mais j’ai rarement vu le cas pour les précédentes, donc ça devrait aller.

slices sur les générateurs

Les générateurs, c’est formidable. C’est iterable. On peut les utiliser partout où on utilise les listes.

Sauf si on doit les limiter en taille.

Alors là, c’est relou.

Par exemple, récupérer les carrés des nombres pairs entre 0 et 100, puis limiter le tout a 10 éléments après le 5e:

from itertools import islice
g = (x * x for x in range(100) if x % 2 == 0)
g = islice(g, 5, 15)

Ca serait tellement plus simple de pouvoir faire:

g = (x * x for x in range(100) if x % 2 == 0)[5:10]

callable dans les slices

Si vous voulez tous les carrés des nombres au-dessus de 5, vous pouvez faire:

(x * x for x in numbres if x > 5)

Mais si vous voulez tous les nombres à partir du moment où vous rencontrez un nombre au-dessus de 5 ?

from itertools import dropwhile
numbers = dropwhile(lambda x: x > 5, numbers)
(x * x for x in numbres)

Alors certes, je ne suis pas pour transformer Python en Haskell et balancer des formules magiques comme:

(x * x for x in numbers[a -> a > 5])

Mais juste m’éviter l’import et pouvoir faire ça:

def start(x):
    return x > 5
(x * x for x in numbers[start:])

Ca serait cool.

with var dans les expressions génératrices

Je suis hésitant sur cette feature car c’est très tentant de faire des one liners trop longs avec, mais:

(x.split()[1] for x in truc if x.split()[1] == 1)

C’est con de faire 2 fois split quand même.

(y for x in truc 
   with x.split()[1] as y 
   if y == 1)

Bon, ça peut rapidement devenir illisible, donc à méditer.

async optionnel

Je cherche toujours à comprendre pourquoi async est nécessaire.

Avec les générateurs, la présence de yield fait détecter automatiquement la fonction comme fonction génératrice:

def stuff(): # pas de machin def
    yield bidule # python comprends que c'est un générateur

Avec await, ça devrait être pareil:

def stuff():
    await bidule # bim, c’est une coroutine !

Pas besoin de async. Si on veut faire une coroutine sans un seul await, il y a toujours @asyncio.coroutine.

async reste très utile pour async for et async with, mais perso j’aurais préféré avoir un await with et un await for et pas de async.

On peut imaginer l’inverse aussi : tabler sur “explicit is bettern than implicit” et rajouter un gen def pour les générateurs et obtenir la parité.

Après, le prenez pas mal hein. J’adore async/await. Vive asyncio ! Mais la syntaxe pourrait être plus cohérente, plus proche du comportement des générateurs, puisqu’un coroutine n’est qu’un générateur spécialisé.

Paramètres sympas pour pytest 2

vendredi 29 janvier 2016 à 13:19

En Python, pas la peine de faire des tests sans pytest.

Et avec quelques options, pytest devient encore plus pratique:

py.test -vv --capture=no --showlocals --exitfirst

Détaillons.

-vv déclenche le mode extra-verbeux, qui affiche le nom de chaque test qui passe ainsi que plein de détails en cas d’échec.

--capture=no permet d’utiliser print() et pdb dans vos tests unitaires.

--showlocals affiche les variables locales de tout test qui échoue.

--exitfirst arrête les tests dès le premier échec plutôt que de faire toute la liste.

Grace au paramètre addopts, vous pouvez passer ces paramètres par défaut à py.test.

Soit par la variable d’environnement PYTEST_ADDOPTS, par exemple en mettant dans votre bashrc:

export PYTEST_ADDOPTS="-vv --capture=no --showlocals --exitfirst"

Ou en mettant dans le fichier de config (comme tox.ini)

[pytest]
addopts = -vv --capture=no --showlocals --exitfirst

Les plans à quatre ne sont pas mystérieux 8

jeudi 28 janvier 2016 à 12:09

Avec Comment arrivent les plans à 3 et Le sperme ça attache au fond, je vous avais déjà montré que les expériences sexuelles qu’on qualifie d’inhabituelles n’arrivent pas suite à des rituels d’incantations mystiques.

Il en va de même pour le plan à quatre.

Ce soir-là je raccompagne chez elle une demoiselle très expérimentée dans le domaine de la coquinerie. Arrivés devant le portail, l’attendent deux de ses amis qui, et c’est important, ne s’étaient pas concertés pour venir. L’un amène l’apéritif.

À ce stade-là, le quatuor en rut majeur n’est pas programmé.

Néanmoins, je connaissais les personnes. Je savais qu’elles étaient sexuellement à l’aise et avaient déjà fait des choses de ce genre: strip-poker, striptease, plan à trois… Leurs histoires sont connues, et certaines avaient couché ensemble.

J’ai donc mentalement pris note qu’un travail d’équipe était possible.

Nous avons servi quelques verres, sur des discussions anodines.

La maitresse des lieux annonce qu’elle a mal aux pieds, et me demande un massage, activité pour laquelle tout mon entourage sait que je suis très qualifié. On concocte nos propres huiles dans la famille.

Maitresse coquine partage son enthousiasme à haute voix, et invite sa consœur à essayer. Je change donc de pieds, et j’y vois une opportunité.

Je propose ainsi au 4e de profiter de l’occasion pour apprendre quelques mouvements afin de ne pas laisser les orteils de ma cliente précédente refroidir.

Là on a une bonne base : 4 adultes consentants et expérimentés, dans l’intimité d’un appartement, ayant bu, se tripotant les uns les autres.

Parti de là, le reste n’est que gamineries, littéralement. Fausses excuses pour se toucher plus haut, « t’es pas cap » et autre « allezzzzzz ». J’embrasse l’une. On pousse un peu les filles à s’embrasser.

C’est très peu subtil, personne n’est dupe, mais c’est la nature humaine : on ne peut pas juste dire « allez on s’encule ! ». Il faut un prétexte, fût-il bidon.

L’un fera celle qui est un peu gênée.

L’autre fera celui qui est un peu étonné.

Et c’est tout.

Notez encore une fois le contexte habituel :

Bref, ça baise, ça suce, ça lèche, ça caresse. Tout le monde est très gentil, sourit beaucoup. Un des acteurs a du mal à bander. C’est normal. Ces plans à plusieurs foutent la pression, et ça arrive régulièrement. Il faut rassurer la personne, et proposer des activités qui n’impliquent pas de pénétration en attendant.

Et là vous voyez, pas de mystère. Pas de secrets incroyables.

Je vous le répète : le sexe, c’est la dinette des adultes.