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 [2015-09-07T18:24:50.735465+00:00]>
>>> arrow.utcnow().replace(months=+3, weeks=-1, hours=+1)
             <Arrow [2015-11-30T19:25:03.887149+00:00]>
>>> arrow.utcnow().to('US/Pacific')
             <Arrow [2015-09-07T11:25:44.859458-07:00]>
>>> arrow.now().replace(minutes=-3).humanize(locale='fr')
             'il y a 3 minutes'
>>> arrow.get('2013-09-29T01:26:43.830580')
             <Arrow [2013-09-29T01:26:43.830580+00:00]>

Ouai.

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/<filename:path>')
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

38 thoughts on “Sept petites libs qui changent la vie d’un dev Python

  • Sam Post author

    @desfrenes

    Clize fait à peu prêt la même chose que Argh, mais à l’usage j’ai trouvé Clize plus intuitif, et le code tient dans un tout petit fichier.

    • Sam Post author

      Wow un mec de l’april ?

      Bienvenu :-) J’adore ce que vous faites. Je suis donateur. Longue vie à l’APRIL, tout ça.

  • Muchos

    C’est vraiment génial Python ! Je n’y connais rien dans ce langage, mais son nom est *sur* et *dans* tous les projets informatiques que je lorgne çà et là…

    En plus, la syntaxe est visiblement réussie et les “piles incluses” excellentes :) Grâce à vous, je carbure au python -m "SimpleHTTPServer" pour tester mon site en local… mais ça ne fonctionne pas avec php…

  • Recher

    Ouah cool. Merci beaucoup !

    Clize est une super bonne idée. Maintenant que je l’ai sous les yeux, je me rends compte que y’avait effectivement un manque, pour un problème aussi con que la récupération d’arguments.

    Sinon, comme librairie top classe, j’aime bien logging.
    – Formatage de message de log.
    – Définition de niveaux (error, warning, info, blabla, …)
    – Emission vers stdout, fichier texte, mail, etc.
    – Thread safe
    – Morceau de brennek rôti.

  • Sam Post author

    @desfrenes et @Recher: Attention avec PHP -S, c’est un ajout très récent (PHP 5.4.0) et donc n’est pour l’instant pas disponible partout. Par exemple le PHP des dépots de la dernière Ubuntu (Precise Pangoline) est en version en 5.3. Inutile de dire que les hébergeurs ne seront pas à jour de si tôt.

    Néanmoins si vous utilisez un framework PHP (comme Symphony ou CakePHP), il y a fort probablement un server de dev fourni avec comme c’est le cas pour Django et Bottle en Python

    • Sam Post author

      Pas exactement. En fait un serveur de dev est un moyen fabuleux de débugger en ligne sur un autre port en 2 secondes un problème en prod qu’on ne peut débugger en local. Ca permet de faire le debuggage sans perturber l’expérience utilisateur, et même activer les modes DEBUG sans que ça se voit, voir carrément tester 4 setup avec 4 settings différents sur 4 autres ports en parallèle. Ces petits serveurs de dev sont fabuleux.

      Excellent pour dotdeb, je connaissais pas.

  • desfrenes

    C’est pas une mauvaise idée effectivement.

    Pour les frameworks, à ma connaissance il n’y a pas de framework php qui fournisse son serveur de dev, pas avant php5.4, même si on connait des projets visant à faire un serveur web en php (à grands coups de pcntl souvent).

  • Max

    Moi chui du mois de Mai mais je pense que tout le monde s’en fout…

  • Sam Post author

    lxml ne gère pas du tout le HTML. Il gère le xml. Du coup pour tout ce qui est HTML 4 et HTML 5, lxml est à la ramasse, surtout sur du mal formé.

  • askiz

    @Sam: tu y vas un peu fort avec lxml en disant qu’il ne gère pas du tout le HTML..

    Je l’utilise pour quelques tools pour parser des pages HTML et exécuter des query XPATH. Je n’ai jamais eu de problème :).

  • Sam Post author

    C’est parce que tu travaille sur des pages bien formées (ou du xHTML). Mais parser des pages en HTML4 ou 5 fait avec la méthode rache, ça pardonne vachement moins.

  • askiz

    @sam: C’est fort probable. Je check ce soir.

    Dans tous les cas, c’est tout de même possible et, au moment ou j’ai fais mes scripts (2/3 ans), c’était bien pratique pour effectuer des requêtes XPATH non gérées par Beautiful Soup (c’est le cas maintenant ?).

  • Etienne

    C’est peut-être un peu hors sujet, mais j’ai un problème ennuyeux avec peewee. Y’a quelqu’un qui peut me dire où je peux poster ça?

    J’ai posté sur google groups, mais c’est un peu mort…

  • Sam Post author

    Si c’est un bug: sur le bug tracker de peewee (je pense qu’il est sur github). Si c’est une demande d’aide, sur le forum de l’afpy pour du fr, et sur stackoverflow pour du en de haut niveau.

  • Sam Post author

    D’ici un an ou deux, on aura éradiqué toutes les fautes de tous les articles, mouahahaha !

    Après on s’attaquera aux comments.

    Nan je déconne…

  • s13d

    Je connaissais pas begins, merci ! J’utilisais plutôt docopt jusqu’à présent, mais je vais peut-être essayer cette trouvaille ;-)

  • blop

    Merci pour l’update, sinon, dans quels cas vous utilisez botlle et dans quels cas Flask ? C’est quoi l’intérêt de bottle par rapport à Flask si ce n’est d’être embarquable dans un projet en un seul fichier, et éviter un nouvelle dépendance ?

  • Sam Post author

    C’est le seul avantage. Je n’utilise jamais flask. Soit j’ai besoin d’un tout petit truc, et je fais du bottle, soit j’ai besoin de plus, et je fais du django. flask représente un niveau intermédiaire donc je n’ai jamais eu besoin.

  • Laurent

    Salut !

    Je suis un graaaand fan du site

    Pourriez-vous juste rajouter dans la section “path.py” qu’il s’installe avec un

    pip install path.py

    histoire de capitaliser et d’être homogène avec les autres libs :)

    Et si ça vous plait, j’adorerai lire sur les bonnes pratiques, quelques exemple typiques un peu barbus et que tout le monde échange sur les moyens d’implémenter… Avec des moyens de voter sur la meilleure solution (perfo/reuse/élégance, etc.)

    Merci pour votre partage !!

  • Sam Post author

    Pourriez-vous juste rajouter dans la section “path.py” qu’il s’installe avec un

    Yes !

    quelques exemple typiques un peu barbus et que tout le monde échange sur les moyens d’implémenter

    Les moyens d’implémenter quoi ? Les bonnes pratiques sur quoi ?

    Avec des moyens de voter sur la meilleure solution (perfo/reuse/élégance, etc.)

    Ca c’est pas pour demain :) On va pas modifier le code de wordpress, et je doute qu’il y est un plugin solide pour ça.

  • Anne Onyme

    Plop

    “page d’acceuil” -> “page d’accueil”;
    “/chemin/vers/dossier/des/fichiers/statiques/cs” -> “/chemin/vers/dossier/des/fichiers/statiques/css”;
    “text” -> “texte” (2 fois);
    “En a déjà parlé” -> “On en a déjà parlé”.

    Sinon, je ne comprend toujours pas bien l’intérêt de Bottle alors qu’il y a Flask, qui n’est pas plus compliqué à prendre en main et permet aussi de monter son site web en 5 minutes chrono. Dit autrement, en quoi Flask est-il moins intéressant que Bottle pour les petits projets?

    Sinon, pour ceux que ça intéresse, une comparaison d’autres libs pour parser des arguments: https://realpython.com/blog/python/comparing-python-command-line-parsing-libraries-argparse-docopt-click/.

  • Sam Post author

    bottle tient dans un fichier, donc tu peux l’embed, c’est tout. Le reste n’est pas mieux. Mais si je veux plus, je prendrais django de toute façon.

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.