Question

Je souhaite appeler un processus via un programme python. Toutefois, ce processus nécessite certaines variables d'environnement spécifiques définies par un autre processus. Comment puis-je faire en sorte que les premières variables d’environnement de processus les transmettent à la seconde?

Voici à quoi ressemble le programme:

import subprocess

subprocess.call(['proc1']) # this set env. variables for proc2
subprocess.call(['proc2']) # this must have env. variables set by proc1 to work

mais le processus à traiter ne partage pas le même environnement. Notez que ces programmes ne sont pas les miens (le premier est un fichier .bat volumineux et laid, et le second est un logiciel propriétaire). Je ne peux donc pas les modifier (d'accord, je peux extraire tout ce dont j'ai besoin du .bat, mais c'est très complexe. ).

NB: J'utilise Windows, mais je préfère une solution multiplate-forme (mais mon problème ne se produirait pas sous Unix-like ...)

Était-ce utile?

La solution

Puisque vous êtes apparemment sous Windows, vous avez besoin d'une réponse Windows.

Créez un fichier de commandes wrapper, par exemple. "run_program.bat", et exécutez les deux programmes:

@echo off
call proc1.bat
proc2

Le script s'exécutera et définira ses variables d'environnement. Les deux scripts s'exécutant dans le même interpréteur (instance cmd.exe), les variables prog1.bat seront donc définies lors de l'exécution de prog2.

Pas très beau, mais ça va marcher.

(Peuple Unix, vous pouvez faire la même chose dans un script bash: "source file.sh".)

Autres conseils

Voici un exemple montrant comment extraire des variables d’environnement d’un fichier batch ou cmd sans créer de script wrapper. Profitez.

from __future__ import print_function
import sys
import subprocess
import itertools

def validate_pair(ob):
    try:
        if not (len(ob) == 2):
            print("Unexpected result:", ob, file=sys.stderr)
            raise ValueError
    except:
        return False
    return True

def consume(iter):
    try:
        while True: next(iter)
    except StopIteration:
        pass

def get_environment_from_batch_command(env_cmd, initial=None):
    """
    Take a command (either a single command or list of arguments)
    and return the environment created after running that command.
    Note that if the command must be a batch file or .cmd file, or the
    changes to the environment will not be captured.

    If initial is supplied, it is used as the initial environment passed
    to the child process.
    """
    if not isinstance(env_cmd, (list, tuple)):
        env_cmd = [env_cmd]
    # construct the command that will alter the environment
    env_cmd = subprocess.list2cmdline(env_cmd)
    # create a tag so we can tell in the output when the proc is done
    tag = 'Done running command'
    # construct a cmd.exe command to do accomplish this
    cmd = 'cmd.exe /s /c "{env_cmd} && echo "{tag}" && set"'.format(**vars())
    # launch the process
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=initial)
    # parse the output sent to stdout
    lines = proc.stdout
    # consume whatever output occurs until the tag is reached
    consume(itertools.takewhile(lambda l: tag not in l, lines))
    # define a way to handle each KEY=VALUE line
    handle_line = lambda l: l.rstrip().split('=',1)
    # parse key/values into pairs
    pairs = map(handle_line, lines)
    # make sure the pairs are valid
    valid_pairs = filter(validate_pair, pairs)
    # construct a dictionary of the pairs
    result = dict(valid_pairs)
    # let the process finish
    proc.communicate()
    return result

Donc, pour répondre à votre question, vous devez créer un fichier .py qui effectue les opérations suivantes:

env = get_environment_from_batch_command('proc1')
subprocess.Popen('proc2', env=env)

Comme vous le dites, les processus ne partagent pas l'environnement. Par conséquent, ce que vous demandez littéralement n'est pas possible, pas seulement en Python, mais avec n'importe quel langage de programmation.

Ce que vous pouvez faire, c'est placer les variables d'environnement dans un fichier ou dans un tube, puis

.
  • demandez au processus parent de les lire et transmettez-les à proc2 avant la création de proc2, ou
  • demandez à proc2 de les lire et de les définir localement

Ce dernier nécessiterait la coopération de proc2; le premier nécessite que les variables soient connues avant le démarrage de proc2.

Deux choses me viennent à l’esprit: (1) faire en sorte que les processus partagent le même environnement, en les combinant d’une manière ou d’une autre dans le même processus, ou (2) que le premier processus produise une sortie contenant les variables d’environnement pertinentes, afin que Python puisse lisez-le et construisez l'environnement pour le second processus. Je pense (même si je ne suis pas tout à fait sûr) qu'il n'y a aucun moyen d'obtenir l'environnement d'un sous-processus comme vous espérez le faire.

Le multitraitement du module standard Python possède un système de files d'attente qui vous permet de passer en mode pickle. objet -able à passer à travers les processus. Les processus peuvent également échanger des messages (un objet décapé) à l'aide de os.pipe. N'oubliez pas que les ressources (par exemple, la connexion à une base de données) et le descripteur (par exemple, les descripteurs de fichier) ne peuvent pas être traités.

Vous pouvez trouver ce lien intéressant: Communication entre processus avec multitraitement

Le PyMOTw sur le multitraitement mérite également d’être mentionné: Principes de base du multitraitement

désolé pour mon orthographe

L'environnement est hérité du processus parent. Définissez l'environnement dont vous avez besoin dans le script principal, et non un sous-processus (enfant).

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