atom, script, python et virtualenv

temps de lecture : 7 min

Si vous utilisez atom et python, alors vous cherchez peut-être à bénéficier de l’exécution de votre programme en cours de développement directement dans l’éditeur tout en utilisant virtualenv.
Après pas mal de recherches sur le net pour un projet de mon fils, nous sommes parvenus à cette solution.

Lorsque l’on développe en python, utiliser virtualenv est une très bonne pratique. Cette solution permet de ne pas avoir à installer des modules sur son poste et par conséquent ne pas avoir à gérer des incompatibilités de version entre les packages des différents programmes. Ceci permet également de disposer pour des outils d’intégration continue qui peuvent ainsi positionner le test du programme dans un environnement totalement neuf.

En règle générale, on initie un environnement virtuel, on y installe l’ensemble des ses modules, souvent sur la base du fichier requirements.txt et on peut alors exécuter son programme ou les tests s’y référents. En sortant de l’environnement virtuel, on retrouve son poste comme neuf, on peut même le détruire sans impact sur son poste.

Dans l’environnement de développement atom, on peut via le package script lancer l’exécution de tout ou partie de son code, indépendamment du langage par ailleurs. Le soucis de cette solution est que la partie virtualenv n’est pas utilisée. Voici donc de quoi le faire assez simplement sans chercher trop longtemps sur le net, peu de documentation facilement accessible à ce sujet.

Vous trouverez le contenu des fichiers et un exemple dans mon repo git atom-py-startup.

Dans votre code python

Il faut se mettre dans une situation permettant à ce qu’une exécution depuis atom (ou hors de virtualenv en général) puisse se positionner dans l’environnement virtuel avant de réellement s’exécuter.

Je propose pour ce faire de placer dans le fichier __main__.py de quoi effectuer les actions suivantes :

  • vérifier si l’environnement virtuel est créé
  • le créer le cas échéant et installer les dépendances depuis requirements.txt
  • se positionner dedans
  • lancer le contenu du programme réel situé dans main.py

La partie importante permettant l’exécution dans le virtualenv est fourni par le fichier activate_this.py installé dans chaque environnement (à côté de activate). Afin de l’utiliser voici le bout de code qui fonctionne aussi bien en python 2 que 3.

__main__.py
1
2
3
4
5
6
7
8
9
10
11
12
def execInEnv(envname="env", globals=None, locals=None):
""" run the current program in a virtualenv """
logging.info('running in virtualenv: '+envname)
if globals is None:
globals = {}
filepath = envname + "/Scripts/activate_this.py"
globals.update({
"__file__": filepath,
"__name__": "__main__",
})
with open(filepath, 'rb') as file:
exec(compile(file.read(), filepath, 'exec'), globals, locals)

Rien de bien complexe, on lit le fichier en question, on le compile, le positionne dans un contexte approprié à l’utilisation de la commande exec.

Il suffit alors de l’appeler avec une commande passant le nom de l’environnement (qui est créé dans le répertoire contenant le code), par défaut il utilisera env :

__main__.py
1
execInEnv(env)

Dans atom

L’éditeur, via le package script, exécute par défaut une commande python avec le nom du fichier courant. Ici, on souhaite exécuter l’ensemble du programme, pour cela il faut demander à python de démarrer sur le répertoire de celui-ci avec la commande

1
python .

Ceci va pousser python à exécuter le contenu du fichier __main__.py.

Dans les options d’exécution de script (CTRL+SHIFT+ALT+O) on positionne dans le champ Command Arguments la valeur {PROJECT_PATH} que atom remplacera au moment de l’exécution par la racine du projet.

Dans les paramètres du package script, on positionnera également le fonctionnement du CWD (current working directory) à Project directory of the script, ceci afin que le programme ait pour racine d’exécution celui du projet.

Désormais, en étant dans l’édition d’un fichier python, le lancement de l’exécution (CRTL+SHIFT+B) vous positionnera dans l’environnement et le créera s’il n’était pas présent.

Utiliser une autre version de python

Si le python par défaut de votre poste de travail est différent de celui que vous souhaitez dans votre environnement virtuel, il faudra alors renseigner les champs suivants dans les options d’exécution :

  • command = chemin vers votre binaire python
  • command argument = {PROJECT_PATH}
  • environnement variables : VIRTUALENV_PYTHON=[chemin vers votre binaire python]

Ceci permettra de construire le virtualenv avec la bonne version de python et de l’exécuter également avec cette version car la solution proposée ici ne change pas la version de python pendant le passage dans l’environnement virtuel.

Par exemple ici, sur un environnement windows, on positionne l’ensemble pour fonctionner sur une version 2.7 de python :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2018-10-14 17:41:13,982 [INFO] __main__.py:54 - python version: 2.7.15 [...]
2018-10-14 17:41:13,982 [INFO] __main__.py:72 - create virtualenv env, not existing yet
New python executable in [...]
Installing setuptools, pip, wheel...done.
Running virtualenv with interpreter D:\apps\Python\Python27\python.exe
2018-10-14 17:41:35,750 [INFO] __main__.py:42 - running in virtualenv: env
2018-10-14 17:41:35,752 [INFO] __main__.py:81 - install libraries from reqs
Collecting numpy (from -r requirements.txt (line 2))
Using cached ...
Collecting redis (from -r requirements.txt (line 3))
Using cached ...
Installing collected packages: numpy, redis
Successfully installed numpy-1.15.2 redis-2.10.6
2018-10-14 17:41:51,529 [INFO] __main__.py:85 - python version: 2.7.15 [...]
ok
[Finished in 37.686s]

On constate bien que la version est bien celle souhaitée en ligne #5 pour le virtualenv ainsi que pour l’exécution depuis script en ligne #1.
Les packages installés dans l’environnement virtuel sont ceux positionnés dans requirements.txt, comme convenu.

La ligne ok en #15 est le résultat de notre programme main.py qui importe une librairie redis pour tester (en dehors du virtualenv, ce programme ne fonctionne pas car la librairie n’est pas installée sur mon poste).

Je suis preneur d’amélioration, n’hésitez pas dans le git ou en commentaire de ce post.

Photo Jess Watters

Alexandre Chauvin Hameau

2018-10-14T16:47:57