2011-06-10 8 views
31

Quiero llamar a un editor en una secuencia de comandos python para solicitar la entrada del usuario, al igual que crontab e o git commit.llamar a un EDITOR (vim) desde una secuencia de comandos python

Aquí hay un fragmento de lo que he estado ejecutando hasta ahora. (En el futuro, puede ser que utilice $ EDITOR en lugar de vim y para que la gente puede personalizar a su gusto.)

tmp_file = '/tmp/up.'+''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(6)) 
edit_call = [ "vim",tmp_file] 
edit = subprocess.Popen(edit_call,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) 

Mi problema es que mediante el uso de Popen, parece mantener mi E/S con la secuencia de comandos de Python de entrar en la copia en ejecución de vim, y no puedo encontrar una manera de pasar la E/S a vim. Obtuve el siguiente error.

Vim: Warning: Output is not to a terminal 
Vim: Warning: Input is not from a terminal 

Cuál es la mejor manera de llamar a un programa CLI de pitón, control de la mano hacia él, y luego pasar de nuevo una vez que haya terminado con él?

Respuesta

55

Llamar $ EDITOR es fácil. He escrito este tipo de código para llamar editor:

import sys, tempfile, os 
from subprocess import call 

EDITOR = os.environ.get('EDITOR','vim') #that easy! 

initial_message = "" # if you want to set up the file somehow 

with tempfile.NamedTemporaryFile(suffix=".tmp") as tf: 
    tf.write(initial_message) 
    tf.flush() 
    call([EDITOR, tf.name]) 

    # do the parsing with `tf` using regular File operations. 
    # for instance: 
    tf.seek(0) 
    edited_message = tf.read() 

Lo bueno aquí es, las bibliotecas manejan crear y eliminar el archivo temporal.

+0

¡Brillante! Mi única modificación es agregar una reserva en caso de que EDITOR no esté configurado: 'EDITOR = os.environ.get ('EDITOR') si os.environ.get ('EDITOR') else 'vim''. He enviado esto como una edición a su, si desea aceptarlo. – sam

+0

Gracias @sam y @unutbu por sugerencias.No sabía que podía salirse con un '$ EDITOR' no ajustado :) – progo

+0

+1, aunque por alguna razón EDITOR no está configurado en mi Ubuntu. Strange (r) '$ editor' ejecuta Nano donde' crontab -e' ejecuta vim ... – FMCorz

2

El PIPE es el problema. VIM es una aplicación que depende del hecho de que los canales stdin/stdout son terminales y no archivos o tuberías. Quitar los parámetros stdin/stdout funcionó para mí.

Evitaría usar os.system como should ser reemplazado por el módulo de subproceso.

+0

Gracias dmeister. Sin embargo, no funciona para mí. tengo el siguiente código. ¿Es esto lo que querías decir? 'edit_call = [" vim ", tmp_file]; \t edit = subprocess.Popen (edit_call) ' – sam

+0

@sam Sí, eso es lo que quise decir – dmeister

+0

@Sam ¿Qué está pasando? – dmeister

3

En python3: 'str' does not support the buffer interface

$ python3 editor.py 
Traceback (most recent call last): 
    File "editor.py", line 9, in <module> 
    tf.write(initial_message) 
    File "/usr/lib/python3.4/tempfile.py", line 399, in func_wrapper 
    return func(*args, **kwargs) 
TypeError: 'str' does not support the buffer interface 

Para python3, utilice initial_message = b"" para declarar la cadena tamponada.

Luego use edited_message.decode("utf-8") para decodificar el buffer en una cadena.

import sys, tempfile, os 
from subprocess import call 

EDITOR = os.environ.get('EDITOR','vim') #that easy! 

initial_message = b"" # if you want to set up the file somehow 

with tempfile.NamedTemporaryFile(suffix=".tmp") as tf: 
    tf.write(initial_message) 
    tf.flush() 
    call([EDITOR, tf.name]) 

    # do the parsing with `tf` using regular File operations. 
    # for instance: 
    tf.seek(0) 
    edited_message = tf.read() 
    print (edited_message.decode("utf-8")) 

Resultado:

$ python3 editor.py 
look a string 
+0

recibiendo caracteres en blanco de nuevo. Al intentar, en cambio, imprimir (edited_message) 'da como resultado la devolución de' b'''. Esto es con Python 3.5.2 a través de OS X Terminal –

0

paquete python-editor:

$ pip install python-editor 
$ python 
>>> import editor 
>>> result = editor.edit(contents="text to put in editor\n") 

Más detalles aquí: https://github.com/fmoo/python-editor

Cuestiones relacionadas