La première fois que j’avais rencontré path.py
, je l’avais trouvé “juste pratique”, et donc je n’avais pas passé plus de temps dessus. Un jour je me suis poussé à l’utiliser partout dans un projet type “labo” dans lequel je mettais plein de libs à l’épreuve du feu. Force est de constater que sur le long terme, cette bibliothèque fait gagner beaucoup à un projet pour un coût infime. Je l’inclus maintenant par défaut partout.
A quoi sert path.py ?
path.py est typiquement une lib qui ne sert à rien à première vue, car il n’y a rien qu’on puisse faire avec qu’on ne puisse déjà faire avec la lib standard de Python. C’est juste un wrapper autour de os
, os.path
et shutils
. Un peu comme requests pour urllib
en fait.
Elle permet juste de manipuler les fichiers, et chemin de fichiers. C’est tout.
Quel interêt alors ?
L’API est propre, cohérente, simple, intuitive. En un mot, c’est beau. On gagne du temps à l’usage, à la relecture et au debugging, car le code est devenu tout petit et tellement facile à comprendre. Mais le plus fort, c’est que le coût de transition est quasi nul: tout code utilisant path.py est par défault compatible avec le code précédent, sans changer une virgule.
Montre moi
<music>Lunatic Calm - Leave You Far Behind</music>
Installation (ceci dit ça tient dans un fichier…)
pip install path.py |
On importe, et on créer un objet path
à partir d’une chaîne de caractère représentant un chemin de fichier ou de dossier :
>>> from path import path >>> tmp = path('/tmp/') |
Manipuler un chemin de fichier n’a jamais été aussi facile
>>> new = tmp / 'new.txt' # "/" fait os.path.join() >>> new path('/tmp/new.txt') >>> new.isfile() False >>> new.touch() # créer le fichier vide >>> new.isfile() True |
Extraire des données également:
>>> new.ext '.txt' >>> new.name path('new.txt') >>> new.parent path('/tmp') >>> new.parent.parent path('/') |
C’est joli. On en mangerait. Notez que chaque méthode retourne un nouvel objet path()
sur lequel on peut donc appliquer les mêmes méthodes.
En prime, un objet path()
se comporte aussi comme une string:
>>> print new /tmp/new.txt >>> new.upper() '/TMP/NEW.TXT' >>> os.path.join(new.parent, 'new_new.txt') path('/tmp/new_new.txt') |
Du coup, aucun problème de migration de l’ancien code. Utiliser path.py
n’a virtuellement que le coût de l’install et de l’import.
On a aussi accès à tout un tas de méthodes avancées:
>>> tmp.dirs() # listing du dossier courant [path('/tmp/pulse-XnVNgklabjGI'), path('/tmp/ssh-vrCzN4692eCp'), path('/tmp/pulse-PKdhtXMmr18n'), path('/tmp/.truecrypt_aux_mnt1'), path('/tmp/.X11-unix'), path('/tmp/.ICE-unix'), path('/tmp/plugtmp'), path('/tmp/pulse-2L9K88eMlGn7'), path('/tmp/orbit-sam'), path('/tmp/.winbindd'), path('/tmp/tracker-sam')] >>> tmp.files() [path('/tmp/new.txt'), path('/tmp/backup_tem.zip'), path('/tmp/qtsingleapp-mediat-134e-3e8-lockfile'), path('/tmp/unity_support_test.0'), path('/tmp/apprentissage-130107043807-phpapp02.odp'), path('/tmp/nIzDHlLoho'), path('/tmp/.X0-lock'), path('/tmp/IDcRs0LUki')] >>> tmp.files('*.txt') # filtres [path('/tmp/new.txt')] >>> tmp.walk() # walk, walkfiles et walkdirs == même chose, récursivement <generator object walk at 0x2e17960> >>> list(path('/etc/php5').walkfiles('*.ini')) [path('/etc/php5/conf.d/10-pdo.ini'), path('/etc/php5/mods-available/pdo.ini'), path('/etc/php5/cli/php.ini'), path('/etc/php5/cli/conf.d/10-pdo.ini'), path('/etc/php5/apache2/php.ini'), path('/etc/php5/apache2/conf.d/10-pdo.ini')] >>> (tmp / 'test/test/test').makedirs() # création récursive >>> (tmp / 'test/test/test').isdir() True >>> (tmp / 'test/test/test').makedirs_p() # les "_p" ignorent certaines erreurs >>> (tmp / 'test/test/test').removedirs() |
Et quelques goodies:
>>> with path('./Work'): print path('.').realpath() print path('.').listdir()[0] ... /home/sam/Work ./A référencer >>> path('~').expanduser() path('/home/sam') >>> path('/etc/fstab').open().readline() '# /etc/fstab: static file system information.\n' >>> new.write_text("BAM d'un coup") >>> new.text() "BAM d'un coup" |
Très pratique dans un shell.
Ça me fait penser à la classe Java File dans certains cas, et a quelques autres fait maison.
En fait ça n’a pas l’air, mais une bonne API de manipulation de chemins de fichiers, c’est indispensable.
pathlib vaut également le détour.
L’essayer c’est l’adopter. Excellent !!
Chouette! Tout simple, tout beau!
J’arrive un peu après la bataille mais pour les suivants:
1) Je n’ai pas trouvé la documentation d’api pour cette lib, ce qui est très curieux car il y a une conf spinx + autodoc sur leur repo github (et que je crois me souvenir qu’il est simple dans ces cas de publié la doc sur readthedoc) du coup j’ai construit la doc (un simple
make html
, c’est ici: documentation api path.py2) Je rencontre un souci avec walkfiles et les fichier contenant des caractères non ascii (le fameux UnicodeDecodeError)
Errata:
concernant le souci d’unicode, il s’avère que je rencontre le même problème avec os.path, cd qui inocente path.py, honte à moi
Pour tout ceux qui ont un problème avec de l’unicode :
sametmax.com/lencoding-en-python-une-bonne-fois-pour-toute/
:-)
Pour info, la doc est là: https://pythonhosted.org/path.py/api.html
Trop bien cette lib, au début j’hésitais à ajouter une dépendance (ouais, même un fichier) mais c’est vraiment trop pratique pour passer à côté.