Se faciliter les imports avec les fichiers *.pth


Dans un article, nous parlions des extensions alternatives en Python, et notamment de l’usage des fichiers *.pth. Néanmoins cette extension est souvent mal comprise, et voici un comment en profiter au maximum.

En Python, on a souvent des problèmes d’import: la lib est dans un dossier au dessous, ou à côté, ou à l’autre bout du disque dur, et ça plantouille parceque Python ne trouve pas le module.

Il existe plein de moyens de jouer avec le fameux PYTHON_PATH qui contient la liste des dossiers dans lesquelles chercher les libs, et la plupart sont fort verbeuses et répétitives, du genre:

import os
import sys
 
CUR_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.extend([
    os.path.join(CUR_DIR, 'apps'),
    os.path.join(os.path.dirname(CUR_DIR), 'libs'),
    os.path.join(os.path.realpath('~'), '.local_libs')
]]}

Une manière simple est d’utiliser un fichier *.pth: on créé un fichier texte, on le nomme comme-on-veut.pth (moi je me fais pas chier, je le nomme .pth comme ça c’est court et c’est caché sous nunux), et on liste tous les dossiers qu’on veut ajouter au PYTHON_PATH, y compris avec des chemins relatifs.

Oui mais, argh parmi les argh, la première fois qu’on le fait, ça ne marche pas. Alors on cherche dans la doc, et là, fustration, on apprend que les fichiers *.pth ne sont parsés que dans les sites directories, c’est à dire les dossiers officiels du système dans lesquels sont censés être les libs de la bibliothèque standard. Donc pas le dossier courant.

Eh oui, ces fichiers ont été conçus pour faciliter les déploiements, du genre quand on fait un setup.py pour son app, pas pour nous, pauvres mortels.

Heureusement il y a une solution Sam et Max à tout, et ici elle consiste à faire:

import os
import site
 
CUR_DIR = os.path.dirname(os.path.realpath(__file__))
site.addsitedir(CUR_DIR)

Quelque part dans son code n’importe où qui est sûr d’être éxécuté tôt, par exemple dans Django, dans le settings.py. Ca ajoute le dossier du projet en tant que site directory, et donc le fichier .pth est parsé. On peut alors dumper son listing dedans sans avoir à le répéter dans tous les scripts et fichiers qui doivent l’utiliser (et ainsi modifier cette liste facilement).

Attention cependant, celà rajoute votre dossier de projet dans le PYTHON_PATH, rendant tout ce qu’il contient importable. Normalement, c’est ce que vous voulez, mais si ce n’est pas le cas, vous pouvez avoir une gestion plus fine en ajoutant juste le fichier .pth avec site.addpackage(CUR_DIR, 'fichier.pth', set())

La feature de magie noire

Dans les fichiers *.pth, il y a un support limité de la syntaxe Python: on peut commenter des lignes avec # et faire des import truc.

Sauf que si vous êtes curieux, vous verrez le détail qui tue dans l’implémentation:

if line.startswith(("import ", "import\t")):
    exec line

On peut donc virtuellement mettre n’importe quel code Python dans les fichiers *.pth. Par exemple:

../foo
import sys; print "Foo a été ajouté au PYTHON PATH"

Va afficher “Foo a été ajouté au PYTHON PATH” au démarrage du programme. Amusant. Et tellement de potentiels pour faire des trucs tordus !

One thought on “Se faciliter les imports avec les fichiers *.pth

  • Lujeni

    Super! Je viens de gagner en clarté pour la gestion de mes import (contexte d’une api RESTful).

    Merci :)

Comments are closed.

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