bottle – Sam & Max http://sametmax.com Du code, du cul Tue, 10 Sep 2019 09:14:50 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Code source du jeu http://sametmax.com/code-source-du-jeu/ http://sametmax.com/code-source-du-jeu/#comments Thu, 25 Jul 2013 12:09:05 +0000 http://sametmax.com/?p=6788 Mraaaah vient d’avoir un compte sur le blog, et peut être aura-t-il le temps de publier les sources de ses solutions. En attendant, voici le code source du jeu.

En général on documente un peu le truc, on met un README, des commentaires, etc. Mais là je vais invoquer le fait que je veux vous montrer ce que ça donne un code à la vite pour justifier ma grosse flemme. Ce code source est intéressant car il montre plusieurs choses :

  • On peut coder en très peu de lignes un truc comme ça en Python.
  • Nous aussi on fait du code à l’arrache : ici un truc pondu en une après-midi, non commenté, écrit d’une traite.
  • Les petites libs comme path.py ou bottle, ça aide bien.
  • Quand on fait les trucs trop vites, il y a des coquilles : dans notre cas on a une lib qui sert à rien, le check du mot de passe final sur la mauvaise fonction, etc. Et c’est pas scalable pour deux ronds.
  • Même quand on code mal en Python, ça reste assez lisible.
  • Python, c’est pas si lent : malgré un code d’init lourd et un serveur en pur Python (cherrypy) qui s’est pris vos essais de bourrins, ça démarre vite et ça a bien tourné.

Vous trouverez dans le répertoire scripts les soluces des énigmes que j’ai utilisé pour vérifier que ça marchait. Vous verrez que là aussi, c’est du vite fait, avec parfois des trucs qui plantent tout simplement par fainéantise.

Pour démarrer le jeu : python site.py avec du 2.7.


Mraaaah a publié ses solutions.

]]>
http://sametmax.com/code-source-du-jeu/feed/ 11 6788
Qu’est-ce que WSGI et à quoi ça sert ? http://sametmax.com/quest-ce-que-wsgi-et-a-quoi-ca-sert/ http://sametmax.com/quest-ce-que-wsgi-et-a-quoi-ca-sert/#comments Wed, 03 Jul 2013 10:36:16 +0000 http://sametmax.com/?p=6544 WSGI est typiquement le cas d'une notion simple et super mal expliquée sur le Web.]]> On va dire que je me répète, mais WSGI est typiquement le cas d’une notion simple et super mal expliquée sur le Web.

C’est terrible ça, une vrai maladie. Ça me donne envie de faire des vidéos comme le joueur du Grenier pour râler à voix haute.

Bref.

Donc WSGI a le même but que FastCGI, SCGI, or AJP : c’est une norme qui sert à définir comment un serveur Python et son application peuvent discuter. Ça été pondu pour que tous les serveurs et toutes les applications Python qui respectent la norme soient garantis de pouvoir s’interfacer.

Ça, c’est la définition que vous voyez partout. Super, mais concrètement ça veut dire quoi ?

WSGI, c’est juste une convention de discussion

Un bon dessin vaut mieux…

Schéma du fonctionnement de WSGI

C'est compliqué de faire un schéma comme ça sérieux ? Ah ça pond une norme de 30 pages mais ça peut pas faire 3 ronds dans paint.

D’un côté vous avez des serveurs comme ceux de cherrypy, de paste, de werkzeug ou comme la commande runserver de Django, ou tels que les serveurs gunicorn, Apache (avec mod_wsgi). Ces logiciels ont pour boulot d’accueillir une requête HTTP et de renvoyer la réponse. Ils ont des problématiques comme : gérer les sockets, gérer plusieurs processus en parallèle, éviter qu’un pirate se balade sur votre serveur, etc.

De l’autre côté vous avez votre application. 9 fois sur 10, votre site Web, donc votre code. Sa problématique c’est de recevoir une requête, la comprendre, et générer une réponse en tapant dans la base de données, et en faisant sa popotte HTML.

Il faut donc que votre serveur dialogue avec votre app, qu’il lui passe la requête, que votre app la gère, retourne la réponse, et file la réponse au serveur. Alors le serveur envoie la réponse au navigateur.

C’est la chose la plus mal expliquée : il y a deux parties à WSGI. Une pour le serveur, et une pour l’application.

Un serveur est dit “compatible WSGI” quand il est capable de transmettre une requête HTTP normale à votre application via le protocole WSGI, et qu’il est capable de récupérer une réponse HTTP depuis votre application via le protocole WSGI pour en faire une requête HTTP normale.

Une application est dite “compatible WSGI” quand elle est capable de recevoir une requête HTTP transformée en un objet Python selon la norme WSGI, et qu’elle retourne une réponse HTTP sous la forme d’un objet Python selon la norme WSGI.

J’avais demandé concrètement, show me the fucking code !

Côté serveur WSGI, on doit lui passer le point d’entrée de votre app.

Le point d’entrée est un module Python qui contient une variable nommé application.

C’est tout.

La variable application doit contenir votre application compatible WSGI.

Une application compatible WSGI a un certain nombre de méthodes pour accepter en paramètres un objet requête HTTP, et retourner un objet réponse HTTP, mais la bonne nouvelle, c’est que vous n’avez absolument pas besoin de savoir comment ça marche.

En effet, tous les frameworks compatibles WSGI (bottle, django, cherrypy, etc) ont une fonction qui retourne cette application toute faite.

Par exemple, avec bottle, mon fichier wsgi va contenir :

from site import app

application = app

C’est tout. app, le décorateur qui permet de faire @app.route('/') dans le code du site bottle, est déjà une application WSGI.

Pour Django, ça va donner un truc comme :

import os
# ont dit quel est le module de settings Django
os.environ["DJANGO_SETTINGS_MODULE"] = "project.settings"

# et on fabrique l'application WSGI avec une fonction
# que Django nous donne
from django.core.wsgi import get_wsgi_application

application = get_wsgi_application()

Le simple fait qu’il y ait une variable nommée application fait que le serveur va se débrouiller. Tout ce qu’il y a à faire, c’est passer en paramètre ce module au serveur, et comment le faire dépend du serveur.

Par exemple pour gunicorn, c’est le premier paramètre de la commande qu’on utilise pour lancer le serveur :

gunicorn nom_du_module

Il faut que le module soit importable (on peut passer l’option --pythonpath pour s’en assurer.)

Pour Apache et mod_wsgi, ça se fait dans le fichier de config apache.conf:

WSGIScriptAlias / /chemin/version/module.wsgi

Bref, faire dialoguer un serveur et une application WSGI, c’est con comme la lune :

  1. Faire un module qui contient une variable nommée application contenant l’app WSGI.
  2. Dire au serveur où se trouve le fichier

Avantages et inconvénients de WSGI

Parmi les avantages, on retrouve :

  • Pas de parsing de la requête au niveau de l’application.
  • Entrée de toutes les apps WSGI normalisées.
  • Tous les logiciels WSGI sont compatibles entre eux.
  • Le module WSGI reste chargé en mémoire une bonne fois pour toute, pas besoin de le recréer à chaque requête.
  • WSGI se suffit à lui même pour écrire une application. Dans la théorie, on n’a même pas besoin de framework.

Quant aux inconvénients :

  • En pratique il y a très peu de code partagé entre les applications WSGI. La communication sur WSGI s’est très mal passée et cela reste quelque chose de mystérieux pour la plupart des développeurs.
  • WSGI ne gère pas les websockets, et la norme est en train d’être mise à jour pour cela. Mais cela prend du temps et les websockets sont déjà là, du coup les gens se tournent vers des solutions non WSGI (tornado, twisted, etc).
  • Certains serveurs ne gèrent pas WSGI (comme nginx ou lighttpd), du coup on ne peut pas communiquer directement entre l’app et eux. Il faut un intermédiaire. C’est pour cela qu’on voit très souvent des setups comme nginx <=> gunicorn <=> django, avec un serveur WSGI qui sert d’intermédiaire. Il y a tout de même le bénéfice de pouvoir gérer parfaitement indépendamment le processus WSGI du serveur HTTP, ce qui est très pratique pour le debug, l’administration système, le déploiement, etc.
  • WSGI, c’est du Python. Qui dit Python, dit import, qui dit import, dit PYTHON PATH. 90% des erreurs de mise en prod sont des erreurs d’import, et pour cette raison sys.path est presque toujours manipulé dans un fichier qui contient une application WSGI.

Pour la culture

Voici à quoi ressemble un hello world en WSGI :

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    yield 'Hello World\n'

Et oui, c’est très simple, et il n’y a rien à importer. La norme WSGI est une convention : il doit y avoir une variable nommée application (ici la variable c’est le nom de la fonction), et cette variable doit contenir une application WSGI.

Mais une application WSGI, c’est juste un callable (ici une fonction) qui accepte en paramètres environ (la requête), start_response (une fonction qui écrit l’en-tête de la réponse) et qui retourne un générateur de string. C’est tout.

Il n’y a rien de magique. C’est une simple interface sur laquelle tout le monde s’est mis d’accord.

Quand on fait en Django:

application = get_wsgi_application()

En fait Django ne fait que fabriquer une fonction comme on vient de voir, qui derrière appelle votre application Django.

En revanche, comme on utilise souvent Django derrière nginx, le setup ressemble très souvent à ça :

Schém d'utilistation de WSGI avec Nginx

Quand on voit "socket", ça fait peur, mais c'est juste une ligne de config qui point généralement vers localhost:8000.

]]>
http://sametmax.com/quest-ce-que-wsgi-et-a-quoi-ca-sert/feed/ 30 6544
Utiliser Cherrypy (serveur web léger) avec Bottle (Framework léger) http://sametmax.com/utiliser-cherrypy-serveur-web-leger-avec-bottle-framework-leger/ http://sametmax.com/utiliser-cherrypy-serveur-web-leger-avec-bottle-framework-leger/#comments Thu, 15 Nov 2012 16:01:38 +0000 http://sametmax.com/?p=3081 Pour les sites/app qu’on developpe en une journée, Bottle et Cherrypy sont deux larons en foire qui s’accouplent parfaitement…

Rappel:

Bottle: Framework python light, allez voir “Créer un site avec bottle en 5 minutes”
Cherrypy: Framework python light + serveur web


Une bonne Pip pour commencer:

monsieur@fion:~# pip install cherrypy

Dans votre fichier start.py:

run(host='0.0.0.0', port=80, server='cherrypy')

Note: le 0.0.0.0 permet d’acceder à votre site depuis l’extérieur.

Pour lancer en daemon vous pouvez utiliser supervisord ou faire un script dans le répertoire où se trouve start.py de votre projet et y coller:

#! /bin/sh

### Run server in daemon mode
nohup python start.py &

Plusieurs serveurs web sur la même machine:
Si vous avez un autre serveur web qui tourne sur votre machine et qui vous empêche de lancer cherrypy sur le port 80 vous pouvez utiliser nginx en proxy. Pour ce faire modifiez le port de cherrypy dans votre fichier start.py (voir plus haut) et réglez-le sur 7777 par exemple avec un host 127.0.0.1.
Ouvrez un fichier de conf nginx et copiez ceci:

upstream monsite_cherrypy {
    server 127.0.0.1:7777;
}

server {
        listen       80;
        server_name monsite.com www.monsite.com ;

        location /favicon.ico {
            root  /home/monsite/static/img;
        }

        location / {
            proxy_pass http://monsite_cherrypy; 
        }

}

Relancez Nginx (service nginx restart). Et votre site est en place. C’est ce qu’on utilise pour multiboards par exemple.

C’est rapide et simple et ça peut tenir pas mal de visiteurs. ça évite d’installer des trucs lourds avec 3 tonnes de config.

]]>
http://sametmax.com/utiliser-cherrypy-serveur-web-leger-avec-bottle-framework-leger/feed/ 21 3081
Récupérer l’IP client avec Nginx en proxy sous CherryPy/Django/Bottle – proxy_set_header http://sametmax.com/recuperer-lip-client-avec-nginx-en-proxy-sous-cherrypy-proxy_set_header/ Thu, 06 Sep 2012 02:11:26 +0000 http://sametmax.com/?p=2041 Si vous utilisez Nginx en proxy, vous allez vous heurter à son IP lorsque votre script tentera de récupérer l’IP du client soit 127.0.0.1.

En rajoutant ces quelques lignes à votre config Nginx:

location / { 
 # ici un proxy pass quelconque
 proxy_pass http://cherrypy;

 # et ici la magie opère
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Dans votre script python (ici Bottle), vous pouvez du coup la récupérer:

#get user IP
user_ip = request.remote_addr
]]>
2041
Le meilleur de l’actu IT fr, le temps d’un café: le multiboards http://sametmax.com/le-meilleur-de-lactu-it-le-temps-dun-cafe-le-multiboards/ http://sametmax.com/le-meilleur-de-lactu-it-le-temps-dun-cafe-le-multiboards/#comments Tue, 14 Aug 2012 19:49:10 +0000 http://sametmax.com/?p=1697 Dans son tuto sur bottle, Max vous disait qu’il avait concocté un exemple de ce qu’on peut faire rapidement avec cette lib.

Ainsi est né multiboards.net.

C’est très simple: il déteste les flux RSS, et veut juste rapidement avoir toutes les infos intéressantes sur l’actu informatique en buvant son kawa le matin, sans se fouler.

Le multiboards répond simplissimement à ce besoin en offrant sur une page qui s’auto refresh :

  • les actus des meilleurs blogs (sélectionnés par le dictateur Max) IT;
  • les actus des meilleurs sites généralistes IT;
  • les offres d’emplois IT en France, principalement Python;
  • des actus plus générales de Google news;
  • tout ça enrobé de conneries pour le lulz venant de imgur, bashfr et vdm;
  • et une radio intégrée dans le menu en haut qui vous diffuse de la zik si vous êtes d’humeur à cliquer dessus.
Capture d'écran du multiboards

Des articles, des news, de bêtises, en un coup d'oeil

C’est du bottle, donc du Python, et massivement du jQuery, avec un petit peut de Redis mais alors vraiment pour la couleur. Car en fait, quasiment tout se passe côté client et ne tape quasiment pas notre serveur. Très KISS.

Il n’y aura pas de version qu’on peut customiser par user, qui demande une registration ou quoique ce soit. Le multiboard, c’est ça, et juste ça.

Maintenant chers amis, il va falloir tous spammer de commentaires ce post pour motiver l’auteur afin qu’il mette le code source sous licence libre. Parceque c’est une feignasse, le Max, je vous le rappelle, et que ça voudrait dire qu’il devrait écrire une doc et nettoyer le random.randint() qu’il a mis pour le compteur de visiteurs.

Ah oui, on a rajouté le lien dans le menu.

 

]]>
http://sametmax.com/le-meilleur-de-lactu-it-le-temps-dun-cafe-le-multiboards/feed/ 25 1697
Créer un site avec bottle en 5 minutes (parceque 7 c’est impossible voyons !) http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/ http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/#comments Mon, 13 Aug 2012 03:55:28 +0000 http://sametmax.com/?p=1660 Aller bande de feignasses c’est Lundi on oublie la murge du week-end et on se secoue les neuronnes !

Bottle est un micro-framework python sur lequel Sam m’a obligé de bosser après Django, (il me force à évoluer c’est une horreur). Je dois dire que je le regrette pas car c’est diablement efficace, mignon et tout et tout.

En début de semaine je me suis dit qu’il fallait que j’en parle, je vais donc vous montrer comment on peut développer un “site” simple en 5 minutes structuré et sans se prendre le choux. Sam viendra compléter mes oublis.

Je ne vais pas aborder la base de données mais il y a plein de plugins bottle ici dont un ORM pour sqlite qu’on détaillera dans un article le jour où on s’en servira ;)

Avant de commencer: Pourquoi je l’aime ?

  • Simple à comprendre
  • bien structuré (des vues des templates, un routing clair)
  • gestion des urls fastoches
  • un petit serveur web intégré, on démarre son site en 10 secondes et on debug avec ipdb
  • une doc formidabuleuse avec des exemples concrets
  • il cracke les watts

En route simone !

On prend la bite rude de créer un environnement virtuel et on fait un pip install bottle. Pour ceux qui veulent tout saloper faites juste un pip install bottle, pour ceux qui savent pas ce qu’est “pip” faites un “wget http://bottlepy.org/bottle.py” dans le dossier de votre projet.

je veux que ça marche tout de suite !

Editez un fichier python start.py à la racine de votre projet et collez ça dedans:

from bottle import Bottle, run

app = Bottle()

@app.route('/')
def hello():
    return "Max est le plus beau!"

run(app, host='localhost', port=8080)

maintenant dans le shell tapez dans le dossier de votre projet où se trouve start.py:

python start.py 
Bottle server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

localhost - - [12/Aug/2012 23:12:15] "GET / HTTP/1.1" 200 21
localhost - - [12/Aug/2012 23:12:16] "GET /favicon.ico HTTP/1.1" 404 742

Ouvrez le navigateur Internet explorer bourré de toolbars à l’adresse 127.0.0.1:8080

C’est bon ça marche, c’est fini, vous êtes un pro du pot. Quand on voit ça on se dit que franchement ça sert à rien de se faire chier plus que ça… :)

Moi quand je vois ça ça me fait chialer à chaque fois tellement c’est simple, je me dis que je vais révolutionner le monde, conquérir la planète, me taper les plus belles meufs…

Avant d’aller plus loin je reprends le code et je note ce qu’il faut retenir

1. le routing

@app.route('/')

@app.route(‘/’) prend tout ce qui arrive à la racine de l’url et le traite dans la vue hello qui est une fonction de base toute simple. si j’avais voulu faire une url du genre 127.0.0.1:8080/samapoil j’aurais mis @app.route(‘/samapoil’)

2. les vues

def hello():
    return "Max est le plus beau!"

la vue est une fonction que l’ont défini et qui peut prendre n’importe quel nom, dedans on traite l’information qui arrivera de l’url routée par le décorateur “@app.route(‘/’)”. Cette vue peut recevoir des infos d’un formulaire ou des variables passées dans l’url (qu’on va voir plus bas)

Voilà votre premier site bottle marche, c’est rigolo. Maintenant on va aller un peu plus loin et utiliser les templates.

Les templates c’est quoi ?
Les templates c’est juste du code HTML avec dedans des “variables” que l’on va peupler dans notre vue. ça sert à ne pas trop mélanger code python et html et c’est plutôt une bonne idée.

Création d’un template:
éditez un fichier template.tpl et mettez dedans

{{ title }}

Maintenant on va assembler le template et la vue comme un légo:
Ouvrez le fichier start.py et collez

from bottle import Bottle, run, view

app = Bottle()

@app.route('/')
@view('template.tpl')
def hello():
    context = {'title': "Max est le plus beau"}
    return (context)

run(app, host='localhost', port=8080)

Relancez le serveur (python start.py) et allez sur à l’adresse 127.0.0.1:8080

Et voilà notre template utilisé par notre vue auquel on a passé un title. Ceci ce fait grace au décorateur “@view” auquel on donne le chemin du template. Les templates offrent pas mal de possibilitées

Les bases sont posées ce n’est vraiment pas sorcier, je rajoute quelques exemples pratiques mais tout ceci figure dans la doc

Mettre un id dans l’url:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from bottle import Bottle, run, view
app = Bottle()

@app.route('/:mon_id')
@view('template.tpl')
def hello(mon_id):
    """
        Récupre la variable mon_id passée dans l'url sous la forme 127.0.0.1:8080/1 et la transmet au template via le context
    """
    context = {'title': "Max est le plus beau %s" % mon_id}
    return (context)

run(app, host='localhost', port=8080)

Récupérer une variable dans l’url:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bottle import Bottle, run, view, request

app = Bottle()

@app.route('/jemesure')
@view('template.tpl')
def hello():
    """
        Récupère la variable taille à l'aide de l'objet request pour l'url 
        http://127.0.0.1:8080/jemesure?taille=133
    """
    context = {'title': "Je mesure %s cm" % request.params.taille}
    return (context)

run(app, host='localhost', port=8080, reloader=True)

Notez le “reloader=True” qui permet au serveur de redémarrer à chaque modif du code, hyper pratique.

Edit:

Servir les images, js, css (appelé contenu statique):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from bottle import Bottle, run, static_file
app = Bottle()

@app.route('/static/')
def server_static(filename):
    """
        Sert les fichiers statiques tel que .js, .css, .jpeg, etc...
    """
    return static_file(filename, root='.')

run(app, host='localhost', port=8080, reloader=True)

Grace à static_file vous pourrez servir vos images, faire télécharger des fichiers, etc, simplement. Dans l’exemple ci-dessus si vous allez sur l’url http://127.0.0.1:8080/static/template.tpl vous allez télécharger le template template.tpl, si c’est une image, votre navigateur affichera une image, etc…

Je vous conseille d’aller voir la doc histoire de vous mettre l’eau à la bouche. JE déteste les docs en général mais là je la trouve presque parfaite.

Sam vous fera un article bientôt sur comment mettre tout ça en prod car le petit serveur web compris dans bottle ne peut bien sur pas assurer une charge en prod.
Mais comme dit ma grand-mère ça se goupille comme un doigt au cul.

Bottle est vraiment pour moi l’outil parfait pour concrétiser rapidement une idée, un site qui ne demande pas une grosse structure, bref un projet qui doit se torcher rapidement ;)

Et pour illustrer ce que j’ai pu faire en quelques jours de taf avec bottle et un peu de Jquery je vous mettrai en ligne dans la semaine un petit site fort symphatique je pense…

]]>
http://sametmax.com/creer-un-site-avec-bottle-en-5-minutes-parceque-7-cest-impossible-voyons/feed/ 20 1660