PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Solution de l’exo la modif de flash

vendredi 21 mars 2014 à 17:25

L’exercice d’hier était plus un prétexte pour faire un peu de Python 3 avec manipulation de bytes qu’un vrai défi, mais c’est toujours marrant.

"""
    Kick flash bin ass so it stop giving us trouble will full screen
    vids on a dual screen.
"""
 
import sys
import argparse
 
# On déclare un argument positionnel obligatoire.
# Ce doit être un fichier que l'on veut
# ouvrir en lecture et mode binaire.
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('bin', type=argparse.FileType('rb'), help="Path to flash bin, man")
args = parser.parse_args()
 
# On charge le contenu du fichier en mémoire.
# Un peu bourrin, mais tellement plus simple
# que de chercher directement dans le fichier.
flash_oh_oooooooh = bytearray(args.bin.read())
# On chercher la chaîne binaire qui correspond à la constante
# qu'on veut écorcher.
if b"_NET_ACTIVE_WINDOW" not in flash_oh_oooooooh:
    print("Flash est déjà défoncé")
    sys.exit(0)
# On remplace juste un bit 
flash_oh_oooooooh[flash_oh_oooooooh.find(b"_NET_ACTIVE_WINDOW") + 1] = 42
 
# On écrit le résultat dans dans le fichier final.
try:
    with open(args.bin.name, 'wb') as news_flash:
        news_flash.write(flash_oh_oooooooh)
except PermissionError:
    sys.exit("Fozzy says you don't have right to write in '%s', man..." % args.bin.name)
 
print("Rosebud")

Voilà, rien d’incroyable, mais on trouve deux choses intéressantes : l’utilisation de FileType pour gérer un paramètre de type chemin de fichier sans se prendre la tête, et celle de bytesarray qui nous permet d’avoir un array mutable et donc de tout charger en mémoire comme un porc sans avoir à dupliquer tout le contenu lors de la modification.

J’ai vu certains ouvrir le fichier sans le flag binaire (‘b’), attention Python peut vous bousiller tout le contenu du fichier puisqu’il va interpréter les caractères spéciaux et faire du décodage sur un contenu sur lequel ça n’a pas de sens.

La vraie question, c’est : combien y a-t-il de références pop culturelles dans ce code ?


Télécharger le code de l’article.

flattr this!

Exercice Python, round 3

jeudi 20 mars 2014 à 11:43

Continuons cette petite série fort sympathique, avec aujourd’hui un peu de manipulation de bytes, de gestion d’erreur et de parsing d’arguments de script.

Souvenez vous de ce hack qui permet d’avoir sa video Flash en plein écran sur un écran, et travailler sur l’autre, quand on est en dual screen. Le problème c’est qu’il faut le faire à la main. De plus, il faut recommencer à chaque mise à jour de flash. On va automatiser tout ça.

Faites un script (en Python 3 \o/) qui va parser les arguments de la ligne de commande avec argparse. Il doit déclarer :

Ensuite on ouvre le fichier, on cherche le fameux _NET_ACTIVE_WINDOW, on le deface, et on sauvegarde le tout dans le fichier final. Ce sera l’occasion de jouer un peu avec la gestion plus propre du binaire en Python 3.

Contrairement aux exercices précédent, on met un minimum de check d’erreur car c’est un petit script (35 lignes copieusement commentées chez moi): donc au moins avertir proprement l’utilisateur si on ne peut pas lire ou écrire dans le fichier et pourquoi.

La solution demain.

flattr this!

Droit de réponse au troll JS

mercredi 19 mars 2014 à 09:17

Comme tous les trolls, on a eu le droit à la cohue dans les comments, mais une réponse a eu l’élégance de faire ça sur un pastebin à part et de structurer l’argumentation.

Et en plus de faire un bisou.

J’aime le droit de réponse, et puisque cette personne n’a visiblement pas de blog (et que ça risque de se perdre dans le fin fond du web), je le publie ici, avec son autorisation.

C’est quand Google a enfin pu donner des perfs décentes – c’est à dire celles qu’ont d’autres langage depuis une décennie – à Javascript que les gens ont envisagé de l’utiliser sur le serveur.

Nan, c’est parce que Ryan Dahl a compris l’importance de la programmation asynchrone et que les gens qui font du JS sont déjà dans le moule de l’asynchrone et que c’était donc une communauté facile à convaincre.
C’est juste une bonne coïncidence qu’au moins une VM très performante est dispo.

Node.js massacre beaucoup d’autres langages en performance grâce à l’asynchrone, pas grand chose d’autre, sûrement pas la “vitesse du langage”.

Javascript (…) ne sert absolument à rien sans un framework côté serveur

On compare des choux et des carottes. Un langage (syntaxe, sémantique) ne sert à rien. Il faut toujours des trucs en plus. Dans un contexte web, à quoi sert Ruby sans Rails ?

côté client il est parfaitement improductif sans une lib pour gommer les incompatibilités entre les implémentations.

Le web est un pari ambitieux qui a des coûts. Mais il faut aussi comprendre les enjeux du web. Aucun téléphone ne sort sans navigateur web aujourd’hui. Ca n’est même pas une discussion. Ca a des coûts qui vont avec. On peut rêver d’un autre monde, mais essayons d’avancer dans celui qu’on a entre temps ;-)

Au cas où vous ne l’aurez pas encore compris, je vomis sur Javascript. Mais je code avec, et j’offre même des formations dessus, car je suis pragmatique. Les besoins de l’industrie, l’inertie technologie et le contexte social / technique / économique dictent bien plus souvent les standards que nous utilisons que leurs qualités intrasèques. Sinon nous n’aurions pas utilisé le format .doc ou les VHS.
En fait, je ne détesterais pas autant Javascript si je n’en avais pas besoin quotidiennement. Je le hais du plus profond de mon âme justement parce que c’est non seulement une contrainte inamovible de mon métier, mais en plus une tumeur que les chercheurs annoncent voir grossir de jour en jour. Avec le sourire, les connards !

Bienvenue dans l’humanité ;-)

Les experts recommandent d’éviter la moitié du langage

Du fat d’être langage du web et de la contrainte de backward-compat du web, JS ne peut pas se débarrasser de ses bad parts. J’ai donné un talk sur le sujet. Être efficace en JS nécessite de comprendre un peu son histoire et les pièges à éviter. C’est le coût d’être le langage du web. Mais c’est bien le web, non ? Ca vaut le coup, non ?

En fait activer use strict dès que possible pour éviter l’insertion de ; automatiques.

wtf? N’importe quoi ! La spec ECMAScript 5 est la référence pour les différences entre strict et “sloppy” mode. Pour des ressources un peu plus digestes :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode/Transitioning_to_strict_mode

Cependant, faites gaffe quand vous convertissez du code parce que :

=> a = 1
1
=> var a = 1
undefined

Mais c’est quoi ce business de la désinformation !!
a = 1 est une expression qui permet de faire a = b = 1, donc sa valeur est la valeur de la sous-expression de droite. var a = 1 n’est pas une expression (if(var a = 1){} est une SyntaxError), donc le REPL se contente de retourner undefined, mais ça n’a aucune importance en pratique.

Ah oui, et ne pas utiliser les mots clés new ou with pour vos propres libs. Si, si, on bannit carrément des mots clés, c’est écrit dans le livre.

Douglas Crockford est une seule personne. On a le droit aussi de ne pas être d’accord. Utiliser with, c’est souvent se tirer une balle dans le pied, d’où le bannissement dans le strict mode. Mais new, c’est plus une question de style. Je suis assez expert JS, j’utilise new et je le vis bien.

Faire du JS propre présuppose l’utilisation de design patterns
En l’état, on ne peut pas écrire du JS propre.

En français aussi, il y a des figures de style. En l’état, on peut écrire du JS propre. Je veux bien admettre que ça exige beaucoup plus de disciplines que d’autres langages, mais ça s’arrête là. Encore une fois, JS est obligé de porter le poids de son histoire parce que c’est le langage du web.

Au fait, vous avez déjà essayé d’expliquer le prototypage à quelqu’un ? Bonne chance !

http://davidbruant.github.io/ObjectViz/

J’ouvre Firefox, je tape [] + {}

J’écris ça quotidiennement aussi, ça m’aide beaucoup pour écrire des interfaces facilement utilisables par les utilisateurs. [] + {} créé aussi des méta-promesses qui permettent de faire de l’asynchrone un peu plus rapide que la vitesse de la lumière.

Si tu additionnes des choux et des carottes, faut pas s’étonner. Si des fois, tu es fatigué, utilise TypeScript pour aider avec la discipline.

chaines multilignes

Ca arrive dans ES6 https://gist.github.com/lukehoban/9303054#template-strings

list compréhension à la Python

ES6 : https://gist.github.com/lukehoban/9303054#comprehensions
Implémenté dans Firefox et dans la Nightly depuis la semaine dernière.

Et encore, je suis cool, je mets un code JS qui utilise l.length directement dans la boucle et pas de variable pour l[i].

Nan, mais c’est bon, on est en 2014, plus besoin de ces conneries :-) Y’en a jamais eu besoin, c’était juste de la micro-optimisations de gens qui pensaient que ça avait un impact significatif après qu’ils aient fait un micro-benchmark sur le sujet.

Array.map arrive avec JS 1.6 et les arrays comprehensions avec la 1.7…

Cute :-)
Array.prototype.map, on peut le polyfiller

JavaScript 1.6, 1.7, ça n’existe pas. C’est des gens chez Mozilla, ils étaient bourrés (Brendan Eich a continué à boire même après avoir créé et shippé JS en 10 jours), ils ont donné des numéros de version, après le mot “JavaScript”, mais c’était pour rire (c’était lié au numéro de version de SpiderMonkey, moteur JS de Firefox). Seuls les numéros de spec d’ECMAScript ont un sens un peu sérieux.

que vous pourrez utiliser sur tous les navigateurs d’ici 2056.

.map tu peux l’utiliser depuis des années. Les array compréhension, ça marche sur Traceur

PASramètre
Comment on fait ça en Javascript ?

Tiens https://gist.github.com/lukehoban/9303054#default–rest–spread
J’ai utilisé ça en TypeScript (mais ceux qui préfèrent Traceur peuvent aussi choisir ça) sur un vrai projet qui tourne sur de vrais mobiles il y a presque un an.

Ah mais il faut utiliser coffeescript !
Oui donc pas Javascript. Point made.

Jeremy Ashkenas, inventeur de CoffeeScript le décrit en disant “it’s just JavaScript”. Je dis ça…

Vous trouvez ça normal ?
Vous trouvez que c’est le signe d’un BON langage ?

Aucune importance. C’est ce qu’on a, il faut vivre avec, bon gré mal gré.

Gros bisous,

David

flattr this!

Réduire la taille de pdf en ligne de commande

mardi 18 mars 2014 à 08:45

Use case : besoin d’envoyer une PDF par email et il fait plus que la taille de pièce jointe autorisée :

gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=sortie.pdf fichier.pdf

Au passage, ça peut servir à concaténer plusieurs fichiers pdf, même si pour bouger, retirer ou ajouter des pages, pdfmod est bien plus pratique.

flattr this!

Ca y est, on peut coder en Python 3

lundi 17 mars 2014 à 12:29

Python 3.4 vient de sortir, et avec cette release, je peux enfin recommander aux gens de se mettre à Python 3 plutôt que Python 2. Tout simplement parce que maintenant, en plus d’avoir énormément de libs qui ont migré, on a l’expérience de la bestiole. C’est stable, les perfs sont bonnes, la conversion de code d’une version à l’autre est bien documentée et maitrisée.

Et surtout, la 3.3 et la 3.4 viennent avec tout un tas des goodies super green.

Voici tout ce dont vous pouvez profiter avec Python 3 que vous ne pouvez pas faire avec Python 2.

Des classes classes

Les classes sont des new type classes en Python 3. Pas besoin d’hériter d’object:

# Au revoir !
class TouteMoche(object):
    pass
 
# Bonjour !
class PropreEtNette:
    pass

Les metaclasses ne se définissent plus comme un attribut spécial :

# Au revoir !
class TouteMoche(object):
    __metaclass__ = UnTruc
 
# Bonjour !
class PropreEtNette(metaclass=Untruc):
    pass

Super Super()

Franchement, qui se souvient de la syntaxe pour appeler proprement la méthode parente d’une classe ?

# Au revoir !
class FranchementHein(object):
 
    def __init__(self):
        super(FranchementHein, self).__init__()
 
# Bonjour !
class FranchementHein:
 
    def __init__(self):
        super().__init__()

Meta meta programmation

Le module inspect permet maintenant de récupérer des infos très très précises sur la signature des fonctions :

    >>> from inspect import signature
    >>> def foo(a, *, b:int, **kwargs):
    ...     pass
 
    >>> sig = signature(foo)
 
    >>> str(sig)
    '(a, *, b:int, **kwargs)'
 
    >>> str(sig.parameters['b'])
    'b:int'
 
    >>> sig.parameters['b'].annotation
    <class 'int'>

Et comme vous pouvez le voir, les annotations sont de la partie.

Les classes ont également un nouvel attribut __qualname__, qui, comme on peut s’y attendre, est le qualified name de la classe :

>>> class C:
...   def f(): pass
...   class D:
...     def g(): pass
...
>>> C.__qualname__
'C'
>>> C.f.__qualname__
'C.f'
>>> C.D.__qualname__
'C.D'
>>> C.D.g.__qualname__
'C.D.g'

Ca marche aussi pour les fonctions.

Enfin pour les gars qui sont vraiment tordus, on a une nouvelle méthode pour les metaclasses, __locallookup__, qui permet d’influencer le MRO à la volée.

Un yield qui yield

Bon, mon titre ne veut rien dire, c’était pour la continuité.

yield a maintenant un petit frère, yield from, qui permet de déléguer l’itération à un itérable sous jacent :

def generateur():
    yield from "123"
    yield from (str(x) for x in range(4, 7))
    yield from ("7", "8", "9")
 
for i in generateur():
    print(i)
 
## 1
## 2
## 3
## 4
## 5
## 6
## 7
## 8
## 9

Là ce n’est pas très utile, mais sur des générateurs complexes, c’est sympa. Surtout que yield from passe aussi les valeur avec send(), fait remonter les exceptions proprement et est détecté par les events loops du module asyncio, dont on parlera plus tard.

Batteries included, with charger

Pip et virtualenv sont livrés avec la 3.4 ! Rien de plus à faire, rien à installer ! Enfin !

Malheureusement pas virtualenv wrapper, mais c’est déjà pas mal.

Un nouveau format, le wheel, permet de faire des paquets binaires qui n’auront pas besoin d’être compilés sur la machine cible. Ca veut dire bientôt du numpy / scipy sans avoir à compiler quoi que ce soit. C’est un remplacement du egg plus simple et sans les problèmes de compatibilités. Il ne vise pas la distribution de projets Python standalones, comme le egg qui a notamment eu le problème de vouloir tout faire en même temps.

Pour ce dernier, le pyz est en discussion.

Enfin les scripts Python supportent maintenant l’équivalent du shebang, mais sous Windows. Ceci vient avec l’introduction de la commande py qui permet de lancer toutes les commandes Python (pip, venv, etc.) pour une version de Python installée spécifique.

Ah, non, pas “enfin”, j’ai oublié un truc :

python -X faulthandler votre_script.py vous permet maintenant d’obtenir une stacktrace sur les scripts utilisant ctypes \o/. Et le module tracemalloc permet d’enquêter sur l’allocation mémoire.

Tout un tas de trucs que les codeurs Java vont adorer

Il y a des Enums, et ça vient sous toutes les formes :

from enum import Enum, IntEnum
 
# La version de feignasse :
Animal = Enum('ant bee cat dog')
 
# La version 'anal retentive'
class Animal(IntEnum):
     ant = 1
     bee = 2
 
# et tout ce qu'il faut entre les deux pour les centristes

Pour les nostalgiques de l’overloading, on peut maintenant spécifier que le code d’une fonction est différent selon le type des arguments qui lui sont passés :

from functools import singledispatch
 
@singledispatch
def fun(arg):
    print('Comportement par défaut, teddy')
 
@fun.register(int)
def _(arg):
    print("Tu m'as passé un int, jonhy !")
 
class Cacatoes:
    pass
 
@fun.register(Cacatoes)
def _(arg):
    print("Tu m'as passé un Cacatoes, billy !")
 
 
fun('Do')
fun([])
fun(1)
fun(Cacatoes)
 
## Comportement par défaut, teddy
## Comportement par défaut, teddy
## Tu m'as passé un int, jonhy !
## Tu m'as passé un Cacatoes, billy !

Et puis le module abc pour faire des classes abstraites, même si ça a été backporté en Python 2.7, donc un peu hors sujet.

Les built-in ont un peu changé

Pour le texte, c’est de l’unicode partout, avec utf8 par défaut pour les conversions. Ca veut dire plus de u devant les chaînes de caractère, plus de déclaration de l’encoding en haut des fichiers de code. Moins de decode / encode.

Mais ça veut dire aussi que open a besoin obligatoirement d’un paramètre encoding, dont la valeur par défaut est bien entendu utf8.

Attention cependant, le built-in bytes n’est pas l’exacte équivalent du type str en Python 2 puisqu’il ne possède plus certaines méthodes de manipulation de texte comme replace:

>>> "Trololo".replace('o', 'a')
'Tralala'
>>> b"Trololo".replace('o', 'a')
Traceback (most recent call last):
  File "<ipython-input-5-f7e93d6f629e>", line 1, in <module>
    b"Trololo".replace('o', 'a')
TypeError: expected an object with the buffer interface

C’est un peu chiant quand on manipule des protocoles binaires, et les mecs de mercurial ont un peu gueulé. Donc il est possible que ça change. J’ai mis beaucoup de fois le mot “peu” dans cet article, ce qui est stylistiquement très laid. Mais je suis trop paresseux pour éditer cet article qui fait maintenant 3 km.

Pour les nombres, on n’a plus à se soucier du type long, qui n’existe plus. / est maintenant la division ordinaire et // la division entière.

Pour les fonctions built-in, pas mal de changements avec bien entendu, print() qui devient une fonction, mais aussi toute ce qui est zip, map, etc, qui retournent des générateurs au lieu de listes, tout comme dict.items et consorts. Ah oui, et import est maintenant absolu par défaut.

Quelques libs en plus

Marre du module os ? pathlib permet de donner un petit goût d'objet à vos manipulations de FS, comme path.py. Ca reste moins bien, mais c'est mieux que rien.

Raz-le bol de recoder la fonction moyenne, médiane, etc ? Le module statistics a été ajouté pour ça.

Enfin, le fameux module mock, qui permet de simuler tout un tas de trucs sans tout casser :

>>> from mock import patch
>>> with patch.object(os, 'listdir', return_value=['file2.txt', 'file2.text']):
    print(os.listdir('/etc/'))
...
[u'file2.txt', u'file2.text']
>>> os.listdir('/etc/')[:2]
[u'environment', u'hosts.allow']

Tout est bien rangé

Les fichiers bytecode Python sont maintenant tous groupés dans un dossier appelé __pycache__. Finis les .pyc qui trainent partout. Et en plus prefixés de l'architecture avec laquelle ils ont été générés. Toujours utile.

En prime pas mal de noms ont été normalisés : tous les modules sont maintenant en minuscule, tous les modules liés à IO sont groupés dans le module io, urllib 1 et 2 ont été mergés, et l'arborescence des exceptions pour les erreurs d'IO a maintenant beaucoup plus de sens :

# Au revoir !
from errno import ENOENT, EACCES, EPERM
 
try:
    with open("document.txt") as f:
        content = f.read()
except IOError as err:
    if err.errno == ENOENT:
        print("document.txt file is missing")
    elif err.errno in (EACCES, EPERM):
        print("You are not allowed to read document.txt")
    else:
        raise
 
# Bonjour !
 
try:
    with open("document.txt") as f:
        content = f.read()
except FileNotFoundError:
    print("document.txt file is missing")
except PermissionError:
    print("You are not allowed to read document.txt")

Asyncio, la prog asynchrone rebootée

Une des raisons pour laquelle je tape sur javascript aussi fort, c'est aussi la jalousie. Ils ont tous les derniers joujoux asynchrones hi-tech, meh !

Avec Python on était obligé d'installer tornado ou twisted pour ça, et c'était un peu dommage :)

Avec la 3.4, la prog asynchrone fait peau neauve (adieu l'horrible module asyncore) et propose de la prog asynchrone plus simple, plus légère, plus facilement intégrable : asyncio.

Si vous lisez ce PEP, ça ne va pas vous parler, alors je vais potasser tout ça et faire un petit article.

Mon seul regret avec asyncio, c'est que c'est un module uniquement bas niveau, alors que tulip, le prototype de la lib, contenait des mobiles haut niveau comme par exemple un client http bien foutu. Du coup ça a donné ce genre de discussion sur le blog, avec des gens qui ne comprenaient pas que je m'attendais à un peu de haut niveau et eux qui ne voyaient que le bas, et donc s'attardaient sur de la sémentique d'implémentation de la prog non blocante.

En conclusion

Le code Python 3 est plus court, plus cohérent, avec moins de surprises, moins de dépendances externes et plus de flexibilité. Des comportements par défaut sains un peu partout, des outils en plus, et comme d'habitude vous n'en utiliserez pas la moitié tellement il y a à faire.

Python 3.4 est vraiment un très bon cru, honnêtement, avec toutes ces améliorations, le langage parvient à se maintenir au niveau des petits jeunes et de leur hype, sans sacrifier sa solidité et sa cohérence.

C'est pour ça qu'on a attendu 5 ans. C'est pour ça que la migration a été lente et prudente.

Parce que la communauté Python fait vraiment les choses bien.

Les exemples du blogs seront donc à partir de maintenant en Python 3.

flattr this!