Abrir documento con la aplicación del sistema operativo predeterminada en Python, tanto en Windows como en Mac OS
Necesito poder abrir un documento usando su aplicación predeterminada en Windows y Mac OS. Básicamente, quiero hacer lo mismo que sucede cuando haces doble clic en el ícono del documento en Explorer o Finder. ¿Cuál es la mejor manera de hacer esto en Python?
Utilice el subprocess
módulo disponible en Python 2.4+, no os.system()
, para no tener que lidiar con el escape del shell.
import subprocess, os, platform
if platform.system() == 'Darwin': # macOS
subprocess.call(('open', filepath))
elif platform.system() == 'Windows': # Windows
os.startfile(filepath)
else: # linux variants
subprocess.call(('xdg-open', filepath))
El paréntesis doble se debe a que subprocess.call()
quiere una secuencia como primer argumento, por lo que aquí usamos una tupla. En los sistemas Linux con Gnome también hay un gnome-open
comando que hace lo mismo, pero xdg-open
es el estándar de Free Desktop Foundation y funciona en entornos de escritorio Linux.
open
y start
son cosas de intérprete de comandos para Mac OS/X y Windows respectivamente, para hacer esto.
Para llamarlos desde Python, puedes usar subprocess
module o os.system()
.
Aquí hay consideraciones sobre qué paquete usar:
Puedes llamarlos a través de
os.system
, lo cual funciona, pero...Escapar:
os.system
solo funciona con nombres de archivos que no tienen espacios u otros metacaracteres del shell en el nombre de ruta (p. ej.A:\abc\def\a.txt
), o de lo contrario es necesario escaparlos. Existeshlex.quote
para sistemas tipo Unix, pero nada realmente estándar para Windows. Quizás vea también Python, Windows: análisis de líneas de comando con shlex- Mac OS X:
os.system("open " + shlex.quote(filename))
- Windows:
os.system("start " + filename)
donde propiamente hablandofilename
también se debe escapar.
- Mac OS X:
También puedes llamarlos vía
subprocess
módulo, pero...Para Python 2.7 y posteriores, simplemente use
subprocess.check_call(['open', filename])
En Python 3.5+ puedes usar de manera equivalente el método ligeramente más complejo pero también algo más versátil.
subprocess.run(['open', filename], check=True)
Si necesita ser compatible desde Python 2.4, puede usar
subprocess.call()
e implementar su propia verificación de errores:try: retcode = subprocess.call("open " + filename, shell=True) if retcode < 0: print >>sys.stderr, "Child was terminated by signal", -retcode else: print >>sys.stderr, "Child returned", retcode except OSError, e: print >>sys.stderr, "Execution failed:", e
Ahora bien, ¿cuáles son las ventajas de utilizar
subprocess
?- Seguridad: en teoría, esto es más seguro, pero de hecho necesitamos ejecutar una línea de comando de una forma u otra; en cualquier entorno, necesitamos el entorno y los servicios para interpretar, obtener rutas, etc. En ninguno de los casos estamos ejecutando texto arbitrario, por lo que no tiene un
'filename ; rm -rf /'
problema inherente de "pero puedes escribir", y si el nombre del archivo puede estar dañado, usarlosubprocess.call
nos brinda poca protección adicional. - Manejo de errores: en realidad no nos proporciona más detección de errores, todavía dependemos de
retcode
en cualquier caso; pero el comportamiento de generar explícitamente una excepción en el caso de un error ciertamente lo ayudará a notar si hay una falla (aunque en algunos escenarios, un rastreo puede no ser más útil que simplemente ignorar el error). - Genera un subproceso (sin bloqueo) : no necesitamos esperar al proceso secundario, ya que, según la declaración del problema, estamos iniciando un proceso separado.
A la objeción "Pero
subprocess
se prefiere". Sin embargo,os.system()
no está obsoleto y, en cierto sentido, es la herramienta más sencilla para este trabajo en particular. Conclusión: por lo tanto, usaros.system()
también es una respuesta correcta.Una marcada desventaja es que el
start
comando de Windows requiere que usted lo pase,shell=True
lo que anula la mayoría de los beneficios de usarsubprocess
.- Seguridad: en teoría, esto es más seguro, pero de hecho necesitamos ejecutar una línea de comando de una forma u otra; en cualquier entorno, necesitamos el entorno y los servicios para interpretar, obtener rutas, etc. En ninguno de los casos estamos ejecutando texto arbitrario, por lo que no tiene un
Yo prefiero:
os.startfile(path, 'open')
Tenga en cuenta que este módulo admite nombres de archivos que tienen espacios en sus carpetas y archivos, por ejemplo
A:\abc\folder with spaces\file with-spaces.txt
( python docs ) No es necesario agregar 'open' (es el valor predeterminado). Los documentos mencionan específicamente que esto es como hacer doble clic en el ícono de un archivo en el Explorador de Windows.
Esta solución es sólo para Windows.