Lorsque vous exécutez des scripts Python depuis la ligne de commande, il est parfois utile de savoir l'emplacement sur le disque du script en cours d'exécution.
C'est un de ces trucs obscurs qui sont pratiquement impossibles à
deviner seul, mais qu'il est simple de se souvenir une fois que vous
l'avez vu. L'élément-clé en est sys.argv. Comme vous
l'avez vu au Chapitre 9, Traitement de données XML, c'est une liste qui contient la
liste des arguments de ligne de commande. Mais elle contient également
le nom du script en cours d'exécution comme il a été appelé depuis la
ligne de commande et cela suffit à déterminer son emplacement.
Indépendamment de la manière dont vous exécutez un script,
sys.argv[0] contient toujours le nom de ce
script, exactement comme il apparaît sur la ligne de commande. Le
chemin peut être inclus ou non, comme nous allons le voir.
os.path.dirname prend un nom de fichier
sous forme de chaîne et en retourne la partie qui représente le
chemin. Si le nom de fichier ne contient pas d'information de
chemin, os.path.dirname retourne une chaîne
vide.
os.path.abspath, l'élément-clé, prend
un chemin, qui peut être partiel ou même vide et retourne un
chemin complet.
os.path.abspath demande une explication plus
détaillée. C'est une fonction très souple, qui peut prendre n'importe
quel type de chemin en argument.
Exemple 16.4. Explication détaillée de os.path.abspath
os.getcwd() retourne le répertoire de
travail en cours.
L'appel de os.path.abspath avec une
chaîne vide retourne le répertoire de travail en cours, comme os.getcwd().
L'appel de os.path.abspath avec un
chemin partiel construit un chemin complet à partir de ce chemin
partiel, basé sur le répertoire de travail en cours.
L'appel de os.path.abspath avec un
chemin complet le retourne simplement.
os.path.abspathnormalise également le chemin qu'il retourne.
Notez que cet exemple marche alors que je n'ai pas de répertoire
'foo', os.path.abspath ne vérifie jamais
votre disque, ce n'est que de la manipulation de chaînes.
Les chemins et noms de fichier que vous passez à
os.path.abspath n'ont pas besoin d'exister sur le
disque.
os.path.abspath ne construit pas seulement
des chemins complets, il les normalise. Cela signifie que si vous êtes
dans le répertoire /usr/,
os.path.abspath('bin/../local/bin') retournera
/usr/local/bin. Il normalise le chemin en le
rendant aussi simple que possible. Si vous voulez normaliser un chemin
de cette manière sans le transformer en chemin complet, utilisez
os.path.normpath.
Exemple 16.5. Exemple de sortie de fullpath.py
[you@localhost py]$ python /home/you/diveintopython/common/py/fullpath.pysys.argv[0] = /home/you/diveintopython/common/py/fullpath.py
path = /home/you/diveintopython/common/py
full path = /home/you/diveintopython/common/py[you@localhost diveintopython]$ python common/py/fullpath.pysys.argv[0] = common/py/fullpath.py
path = common/py
full path = /home/you/diveintopython/common/py[you@localhost diveintopython]$ cd common/py[you@localhost py]$ python fullpath.pysys.argv[0] = fullpath.py
path =
full path = /home/you/diveintopython/common/py
Dans le premier cas, sys.argv[0] inclut
le chemin complet du script. Vous pouvez ensuite utiliser la
fonction os.path.dirname pour enlever le nom
du script et retourner le chemin complet du répertoire,
os.path.abspath retournera simplement ce que
vous lui donnez.
Si le script est exécuté avec un chemin partiel,
sys.argv[0] contient exactement ce qui a été
tapé en ligne de commande. os.path.dirname
vous retournera un chemin partiel (relatif au répertoire en cours)
et os.path.abspath construira le chemin
complet à partir du chemin partiel.
Si le script est exécuté depuis le répertoire en cours sans
donner de chemin, os.path.dirname retournera
simplement une chaîne vide. À partir d'une chaîne vide,
os.path.abspath retourne le répertoire en
cours, ce qui est bien la valeur recherchée puisque le script a
été exécuté depuis le répertoire en cours.
Comme les autres fonctions des modules os et os.path,
os.path.abspath est multiplate-forme. Les
résultats que vous obtiendrez seront légèrement ifférents si vous
utilisez Windows (qui utilise le le
backslash comme séparateur de chemin)
ou MacOS (qui utilise les deux
points), mais le script fonctionnera. C'est là le rôle du module
os.
Addendum. Un lecteur ne s'est pas trouvé satisfait par cette solution, il
voulait pouvoir exécuter tous les tests unitaires depuis le répertoire
en cours, pas celui où regression.py est situé. Il suggère
l'approche suivante :
Exemple 16.6. Exécuter les scripts dans le répertoire en cours
Au lieu de changer le chemin vers le répertoire ou le script
en cours d'exécution est situé, on lui assigne le répertoire en
cours. C'est le répertoire dans lequel vous étiez quand vous avez
lancé le script, qui n'est pas forcément le même que celui dans
lequel se trouve le script (relisez cette phrase jusqu'à que vous
ayez compris).
Ce chemin est ajouté au chemin de recherche des
bibliothèques de Python, de manière à
ce que Python puisse trouver les
modules de tests unitaires lorsque vous les importerez. Vous
n'aviez pas besoin de le faire lorsque le chemin était le
répertoire du script en cours d'exécution, car
Python cherche toujours dans ce
répertoire.
Le reste de la fonction est inchangé.
Cette technique vous permettra de réutiliser ce script regression.py dans d'autres projets. Le
script est mis dans un répertoire commun et vous l'exécutez depuis le
répertoire du projet. Tous les tests unitaires de ce projet sont
trouvés et exécutés, au lieu des tests unitaires du répertoire commun
dans lequel est situé regression.py.