Question

L'accès de Python aux variables d'environnement ne reflète pas fidèlement la vue du système d'exploitation sur l'environnement des processus.

os.getenv et os.environ ne fonctionnent pas comme prévu dans des cas particuliers.

Existe-t-il un moyen d'obtenir correctement l'environnement du processus en cours?

Pour illustrer ce que je veux dire, prenons les deux programmes à peu près équivalents (le premier en C, l’autre en python):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]){
    char *env;
    for(;;){
        env = getenv("SOME_VARIABLE");
        if(env)
            puts(env);
        sleep(5);
    }
}
import os
import time
while True:
    env = os.getenv("SOME_VARIABLE")
    if env is not None:
        print env
    time.sleep(5)

Maintenant, si nous exécutons le programme C et que nous attachons au processus en cours d'exécution avec gdb, nous modifions de force l'environnement sous le capot en procédant comme suit:

(gdb) print setenv("SOME_VARIABLE", "my value", 1)
[Switching to Thread -1208600896 (LWP 16163)]
$1 = 0
(gdb) print (char *)getenv("SOME_VARIABLE")
$2 = 0x8293126 "my value"

alors le programme C mentionné ci-dessus commencera à cracher "Ma valeur" une fois toutes les 5 secondes. Le programme python susmentionné ne le fera cependant pas.

Existe-t-il un moyen de faire en sorte que le programme python fonctionne comme le programme C dans ce cas?

(Oui, je réalise qu'il s'agit d'une action très obscure et potentiellement dommageable à exécuter sur un processus en cours d'exécution.)

De plus, j'utilise actuellement python 2.4. Cela a peut-être été corrigé dans une version ultérieure de python.

Était-ce utile?

La solution

C'est une très bonne question.

Il s'avère que le module os initialise os.environ à la valeur de posix .environ , défini au démarrage de l'interpréteur. En d’autres termes, la bibliothèque standard ne semble pas donner accès à la getenv fonction.

C’est un cas où il serait probablement prudent d’utiliser ctypes sous unix. Puisque vous appelez une fonction libc ultra standard.

Autres conseils

Vous pouvez utiliser ctypes pour le faire simplement:

>>> from ctypes import CDLL, c_char_p
>>> getenv = CDLL("libc.so.6").getenv
>>> getenv.restype = c_char_p
>>> getenv("HOME")
'/home/glyph'

Une autre possibilité consiste à utiliser pdb, ou un autre débogueur python, et à modifier os.environ au niveau python, plutôt qu'au niveau C. Voici une petite recette que j'ai publiée pour interrompre un cours processus python et donne accès à une console python lors de la réception d’un signal. Autrement, collez simplement pdb.set_trace () à un moment donné de votre code que vous souhaitez interrompre. Dans les deux cas, exécutez simplement l'instruction " import os; os.environ ['SOME_VARIABLE'] = 'ma_valeur' ?? " et vous devriez être mis à jour en ce qui concerne python.

Je ne sais pas si cela mettra également à jour l'environnement C avec setenv. Par conséquent, si vous utilisez les modules C directement avec getenv, vous devrez peut-être effectuer un peu plus de travail pour le synchroniser.

Je ne crois pas que beaucoup de programmes s'attendent JAMAIS à voir leur environnement modifié de l'extérieur, donc le chargement d'une copie de l'environnement transmis au démarrage est équivalent. Vous avez simplement trébuché sur un choix d'implémentation.

Si vous voyez toutes les valeurs définies au démarrage et que putenv / setenv fonctionne dans votre programme, je ne pense pas qu'il y ait de quoi s'inquiéter. Il existe des moyens beaucoup plus propres de transmettre des informations mises à jour aux exécutables en cours d'exécution.

Consultation du code source Python (2.4.5):

  • Modules / posixmodule.c récupère l'environnement dans convertenviron () qui s'exécute au démarrage (voir INITFUNC) et stocke l'environnement dans un module spécifique à la plate-forme (nt, os2 ou posix)

  • Lib / os.py examine sys.builtin_module_names et importe tous les symboles de posix, nt ou os2

Alors oui, c'est décidé au démarrage. os.environ ne sera pas utile ici.

Si vous voulez vraiment faire cela, alors l’approche la plus évidente qui vous vient à l’esprit est de créer votre propre module python personnalisé en C, avec un getenv qui appelle toujours l’appel système.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top