Du code, du communisme

Sept petites libs qui changent la vie d’un dev Python

Toutes ces libs sont, bien entendu, installables avec pip.

begins

optparse est deprecated, argparse est imbuvable et sys.argv limité. Avant de vous tirer une balle dans la tête au moment de parser les arguments passés à votre script :

pip install begins

Et voilà, définir des paramètres est aussi simple qu’écrire une fonction :

import begin # pas de 's' ici
@begin.start
def main(argument_obligatoire, argument_optionnel="valeur_par_defaut"):
    """ La docstring est transformée en message d'usage."""
    print(argument_obligatoire, argument_optionnel)

Votre programme accepte maintenant --argument-obligatoire et --argument-optionnel qui seront automatiquement passés à la fonction. --help affichera les options et la docstring :

$ python script.py --help
usage: script.py [-h] [--argument-optionnel ARGUMENT_OPTIONNEL]
               ARGUMENT_OBLIGATOIRE
La docstring est transformée en message d'usage.
positional arguments:
  ARGUMENT_OBLIGATOIRE
optional arguments:
  -h, --help            show this help message and exit
  --argument-optionnel ARGUMENT_OPTIONNEL, -a ARGUMENT_OPTIONNEL
                        (default: valeur_par_defaut)

On peut faire bien plus avec begins : caster les arguments, créer des subcommandes, etc.

arrow

Contrairement à Max, j’adore la gestion des dates en Python. Mais arrow la propulse au niveau supérieur :
pip install arrow
Et hop :

>>> import arrow
>>> arrow.utcnow()
             
>>> arrow.utcnow().replace(months=+3, weeks=-1, hours=+1)
             
>>> arrow.utcnow().to('US/Pacific')
             
>>> arrow.now().replace(minutes=-3).humanize(locale='fr')
             'il y a 3 minutes'
>>> arrow.get('2013-09-29T01:26:43.830580')

Ouais.

Requests

Urllib, ça va 5 minutes. Ça vous dit une API simplissime pour faire des requêtes ?

pip install requests
>>> import requests
>>> requests.post('http://urldelamortquitue.com/magicform/', {u'champ1':u"valeur1", u'champ2':u"valeur2"})

requests gère automamagiquement l’encoding, l’escaping, les cookies, le suivie des redirections et les embouteillages du périph les jours impairs. On peut facilement modifier les headers et cookies, faire des authentifications HTTP, des requêtes HEAD, GET, OPTIONS, PUT, FINGER, NOSE, ASS, ETC.

Bottle

Besoin de monter un mini site Web en 5 minutes ? Bottle est un micro framework Web qui tient en un fichier.

pip install bottle

Et dans un fichier monsite.py:

from bottle import Bottle, run, static_file, view
app = Bottle()
# une page d'acceuil statique
@app.route('/')
@view('home')
def index():
    return {}
# une page de formulaire
@app.route('/truc/create', method='POST')
def create_truc():
    nom_du_truc = request.forms['name']
    # ici faire un machin avec le truc
    return {'name': nom_du_truc}
# afficher un truc en particulier
@app.route('/truc/:truc_id')
@view('truc')
def display_truc(truc_id):
    truc = getTrucFromTrucId(truc_id)
    return {'truc': truc}
# servir les fichiers statiques
@app.route('/static/')
def server_static(filename):
    return static_file(filename, root='/chemin/vers/dossier/des/fichiers/statiques')
if __name__ == "__main__":
    run(app)

On met les templates dans le sous-dossier « views » et les CSS dans « /chemin/vers/dossier/des/fichiers/statiques/css » et
on a un mini site Web qui tourne :

python monsite.py

C’est ce qui fait tourner 0bin.

Peewee

Un ORM qui tient dans un mouchoir de poche, fabuleux pour attaquer une base de données PostgreSQL, MySql ou Sqlite sans avoir à sortir l’artillerie lourde :

pip install peewee

Il y a plusieurs syntaxes pour décrire ses modèles et faire ses queries. L’une d’elles ressemble à celle de l’ORM Django :

import peewee
# exemple avec sqlite
DATABASE_CONNECTION = peewee.SqliteDatabase('/chemin/vers/db.sqlite')
class BaseModel(peewee.Model):
    class Meta:
        database = DATABASE_CONNECTION
class Truc(BaseModel):
    name = peewee.CharField(max_length=256)  # un champ texte limité à 256 chars
    description = peewee.TextField(null=True) # un blob de texte de taille illimitée
    last_update = peewee.DateTimeField(null=True) # un champ date qui peut être nul
class Bidule(BaseModel):
    name = peewee.CharField(max_length=64, help_text=(u"Le nom du bidule"))
    truc = peewee.ForeignKeyField(Truc, related_name='bidules') # chaque bidule est lié à un truc
    valid = peewee.BooleanField(default=False) # un champ vrai/faux
for model in (Truc, Bidule):
    try:
        model.create_table()
    except:
       pass

A l’usage :

# Fabrication des trucs et des bidules
Truc.create(name="cool")
Bidule.create(name="machin", truc=Truc.get(name="cool"))
# et récupération
print("Nombre de trucs: %s" % Truc.select().count())
bidules_du_truc_cool = Truc.get(name="cool").bidules
for bidule in bidules_du_truc_cool:
    print(bidule.name)
    bidule.valid = True
    bidule.save()

Beautiful soup

On en a déjà parlé, mais comme parser du HTML à la main est une plaie, il faut absolument citer cette lib dans cet article.

pip install beautifulsoup

Récupérer toutes les URL des balises scripts qui sont dans le tag HEAD :

head = BeautifulSoup(html).find('head')
links = []
for link in head.findAll('link'):
    href = dict(link.attrs).get('href', '')
    if href:
        links.append(link.attrs)

path.py

La manipulation de fichiers simplifiée :

pip install path.py

Il y en a des concurrents de path.py ! De nombreux ! En fait même dans la stdlib il y a maintenant pathlib qui essaye de se hisser à son niveau.
Et aucun n’y arrive.
La raison principale et qu’ils copient uniquement les fonctionnalités principales, en oubliant tous les petits outils en plus :

>>> from path import Path
>>> root = Path("/etc")
>>> root / 'fstab'
    Path('/etc/fstab')
>>> (root / "nginx" / "nginx.conf").ext
    '.conf'
>>> Path('/tmp/foo.txt').write_text("mouahha", encoding="utf8")
>>> Path('/tmp/foo.txt').text(encoding="utf8")
    'mouahha'
>>> Path.special().user.config
    Path('/home/sam/.config')
>>> Path('/tmp/bar').touch().getmtime()
    1441651642.537244