Sustitución del proceso de estilo Bash con Popen de Python.

En Bash puedes redirigir fácilmente la salida de un proceso a un descriptor de archivo temporal y bash se maneja automáticamente mediante bash de esta manera:

$ mydaemon --config-file <(echo "autostart: True \n daemonize: True") 

o así:

 $ wc -l <(ls) 15 /dev/fd/63 

ver cómo no es la redirección estándar:

 $ vim <(echo "Hello World") vim opens a text file containing "Hello world" $ echo "Hello World" | vim Vim: Warning: Input is not from a terminal 

En el segundo ejemplo, puede ver cómo bash crea automáticamente un descriptor de archivo y le permite pasar la salida de un progtwig a otro progtwig.

Ahora en mi pregunta: ¿Cómo puedo hacer lo mismo con Python, usando Popen en el módulo de subproceso?

    He estado usando un archivo normal de kmers y solo lo he leído, pero mi progtwig ahora genera una lista específica de kmers en tiempo de ejecución en función de los parámetros del usuario. Me gustaría evitar escribir en un archivo temporal manualmente porque tratar con los permisos de archivo podría causar problemas a mis usuarios primitivos.

    Aquí está mi código para ejecutar mi progtwig y capturar la salida estándar con un archivo real “kmer_file”

     input_file = Popen(["pram_axdnull", str(kmer), input_file, kmer_file], stdout=PIPE) 

    Creé una función llamada generate_kmers que devuelve una cadena que puede escribirse en un archivo fácilmente (incluye nuevas líneas) o en un StringIO. También tengo una secuencia de comandos de Python que es independiente para hacer lo mismo

    Así que ahora quiero pasarlo como mi tercer parámetro:

    Esto no funciona:

     kmer_file = stringIO(generate_kmers(3)) input_file = Popen(["pram_axdnull", str(kmer), input_file, kmer_file], stdout=PIPE) 

    Tampoco esto:

     kmer_file = Popen(["generate_kmers", str(kmer)], stdout=PIPE) input_file = Popen(["pram_axdnull", str(kmer), input_file, kmer_file.stdout], stdout=PIPE) 

    Así que me quedé sin ideas.

    ¿Alguien sabe de una buena manera de resolver esto? Estaba pensando en usar la opción shell = True y en usar el bashismo real de <(), pero no lo he descubierto.

    ¡Gracias!

    Si pram_axdnull entiende que "-" convención significa “leer desde la entrada estándar”, entonces podría:

     p = Popen(["pram_axdnull", str(kmer), input_filename, "-"], stdin=PIPE, stdout=PIPE) output = p.communicate(generate_kmers(3))[0] 

    Si la entrada es generada por un proceso externo:

     kmer_proc = Popen(["generate_kmers", str(kmer)], stdout=PIPE) p = Popen(["pram_axdnull", str(kmer), input_filename, "-"], stdin=kmer_proc.stdout, stdout=PIPE) kmer_proc.stdout.close() output = p.communicate()[0] 

    Si pram_axdnull no entiende la convención "-" :

     import os import tempfile from subprocess import check_output with tempfile.NamedTemporaryFile() as file: file.write(generate_kmers(3)) file.delete = False try: p = Popen(["pram_axdnull", str(kmer), input_filename, file.name], stdout=PIPE) output = p.communicate()[0] # or # output = check_output(["pram_axdnull", str(kmer), input_filename, file.name]) finally: os.remove(file.name) 

    Para generar un archivo temporal usando un proceso externo:

     from subprocess import check_call with tempfile.NamedTemporaryFile() as file: check_call(["generate_kmers", str(kmer)], stdout=file) file.delete = False 

    Para evitar esperar a que se generen todos los kmers, es decir, para escribir / leer kmers simultáneamente, podría usar os.mkfifo() en Unix (sugerido por @cdarke):

     import os import shutil import tempfile from contextlib import contextmanager from subprocess import Popen, PIPE @contextmanager def named_pipe(): dirname = tempfile.mkdtemp() try: path = os.path.join(dirname, 'named_pipe') os.mkfifo(path) yield path finally: shutil.rmtree(dirname) with named_pipe() as path: p = Popen(["pram_axdnull", str(kmer), input_filename, path], stdout=PIPE) # read from path with open(path, 'wb') as wpipe: kmer_proc = Popen(["generate_kmers", str(kmer)], stdout=wpipe) # write to path output = p.communicate()[0] kmer_proc.wait() 

    Dar un objeto similar a un archivo a stdin a subprocess.popen constructor.

    Más información aquí

    Y StringIO para obtener un objeto similar a un archivo de cadenas.