usando el subproceso de Python para redireccionar stdout a stdin?

Estoy haciendo una llamada a un progtwig desde el shell utilizando el módulo de subproceso que genera un archivo binario para STDOUT.

Utilizo Popen () para llamar al progtwig y luego quiero pasar la secuencia a una función en un paquete de Python (llamado “pysam”) que desafortunadamente no puede objetos de archivo de Python, pero puede leer desde STDIN. Entonces, lo que me gustaría hacer es que la salida del comando de shell pase de STDOUT a STDIN.

¿Cómo se puede hacer esto desde dentro del módulo de Popen / subproceso? Así es como llamo al progtwig shell:

p = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout 

Esto leerá la salida STDOUT de “my_cmd” y obtendrá un flujo en la p. Ya que mi módulo Python no puede leer directamente desde “p”, estoy intentando redireccionar STDOUT de “my_cmd” de nuevo a STDIN usando:

 p = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True).stdout 

Luego llamo a mi módulo, que usa “-” como marcador de posición para STDIN:

 s = pysam.Samfile("-", "rb") 

La llamada anterior simplemente significa leer de STDIN (denotado “-“) y leerlo como un archivo binario (“rb”).

Cuando bash esto, recibo una salida binaria en la pantalla y no parece que la función Samfile () pueda leerla. Esto ocurre incluso si elimino la llamada a Samfile, así que creo que es mi llamada a Popen el problema y no los pasos posteriores.

EDITAR: En respuesta a las respuestas, he intentado:

 sys.stdin = subprocess.Popen(tagBam_cmd, stdout=subprocess.PIPE, shell=True).stdout print "Opening SAM.." s = pysam.Samfile("-","rb") print "Done?" sys.stdin = sys.__stdin__ 

Esto parece colgar. Me sale la salida:

 Opening SAM.. 

pero nunca pasa la línea Samfile (“-“, “rb”). ¿Alguna idea de por qué?

¿Alguna idea de cómo se puede arreglar esto?

EDIT 2: estoy agregando un enlace a la documentación de Pysam en caso de que ayude, realmente no puedo resolver esto. La página de documentación es:

http://wwwfgu.anat.ox.ac.uk/~andreas/documentation/samtools/usage.html

y la nota específica sobre los arroyos está aquí:

http://wwwfgu.anat.ox.ac.uk/~andreas/documentation/samtools/usage.html#using-streams

En particular:

“” “Pysam no admite la lectura y escritura de objetos de archivo python verdaderos, pero sí admite la lectura y escritura desde stdin y stdout. El siguiente ejemplo lee desde stdin y escribe en stdout:

 infile = pysam.Samfile( "-", "r" ) outfile = pysam.Samfile( "-", "w", template = infile ) for s in infile: outfile.write(s) 

También funcionará con archivos BAM. La siguiente secuencia de comandos convierte un archivo con formato BAM en stdin a un archivo con formato SAM en stdout:

 infile = pysam.Samfile( "-", "rb" ) outfile = pysam.Samfile( "-", "w", template = infile ) for s in infile: outfile.write(s) 

Tenga en cuenta que solo es necesario cambiar el modo de apertura de archivo de r a rb. “”

Así que simplemente quiero tomar el flujo que viene de Popen, que lee stdout, y redirigirlo a stdin, para que pueda usar Samfile (“-“, “rb”) ya que los estados de la sección anterior son posibles.

Gracias.

Estoy un poco confundido de que veas binario en stdout si estás usando stdout=subprocess.PIPE , sin embargo, el problema general es que necesitas trabajar con sys.stdin si quieres engañar a pysam para que lo use.

Por ejemplo:

 sys.stdin = subprocess.Popen(my_cmd, stdout=subprocess.PIPE, shell=True).stdout s = pysam.Samfile("-", "rb") sys.stdin = sys.__stdin__ # restre original stdin 

ACTUALIZACIÓN : Esto asumió que pysam se está ejecutando en el contexto del intérprete de Python y, por lo tanto, significa la entrada estándar del intérprete de Python cuando se especifica “-“. Desafortunadamente, no es así; cuando se especifica “-“, se lee directamente del descriptor de archivo 0.

En otras palabras, no está usando el concepto de Python de stdin (sys.stdin), por lo que reemplazarlo no tiene efecto en pysam.Samfile (). Tampoco es posible tomar la salida de la llamada de Popen y de alguna manera “presionarla” al descriptor de archivo 0; es de solo lectura y el otro extremo está conectado a su terminal.

La única forma real de obtener esa salida en el descriptor de archivo 0 es simplemente moverla a un script adicional y conectar los dos juntos desde el primero. Eso asegura que la salida del Popen en el primer script terminará en el descriptor de archivo 0 del segundo.

Entonces, en este caso, su mejor opción es dividir esto en dos scripts. El primero invocará my_cmd y tomará la salida de eso y lo usará para la entrada a un segundo Popen de otro script de Python que invoca pysam.Samfile (“-“, “rb”).

En el caso específico de tratar con pysam, pude solucionar el problema utilizando una canalización con nombre (http://docs.python.org/library/os.html#os.mkfifo), que es una tubería que puede ser Accedido como un archivo regular. En general, desea que el consumidor (lector) de la tubería escuche antes de comenzar a escribir en la tubería, para asegurarse de que no se pierda nada. Sin embargo, pysam.Samfile (“-“, “rb”) se bloqueará como anotó anteriormente si no hay nada registrado en la entrada estándar.

Suponiendo que se trata de un cálculo anterior que lleva una cantidad de tiempo decente (por ejemplo, ordenar el bam antes de pasarlo a pysam), puede iniciar ese cálculo anterior y luego escuchar en la secuencia antes de que salga algo:

 import os import tempfile import subprocess import shutil import pysam # Create a named pipe tmpdir = tempfile.mkdtemp() samtools_prefix = os.path.join(tmpdir, "namedpipe") fifo = samtools_prefix + ".bam" os.mkfifo(fifo) # The example below sorts the file 'input.bam', # creates a pysam.Samfile object of the sorted data, # and prints out the name of each record in sorted order # Your prior process that spits out data to stdout/a file # We pass samtools_prefix as the output prefix, knowing that its # ending file will be named what we called the named pipe subprocess.Popen(["samtools", "sort", "input.bam", samtools_prefix]) # Read from the named pipe samfile = pysam.Samfile(fifo, "rb") # Print out the names of each record for read in samfile: print read.qname # Clean up the named pipe and associated temp directory shutil.rmtree(tmpdir) 

Si su sistema lo soporta; podrías usar /dev/fd/# nombres de archivo :

 process = subprocess.Popen(args, stdout=subprocess.PIPE) samfile = pysam.Samfile("/dev/fd/%d" % process.stdout.fileno(), "rb")