web-dev-qa-db-fra.com

Document ouvert avec application de système d'exploitation par défaut en Python, sous Windows et Mac OS

Je dois pouvoir ouvrir un document avec son application par défaut sous Windows et Mac OS. En gros, je veux faire la même chose que lorsque vous double-cliquez sur l'icône du document dans l'Explorateur ou le Finder. Quelle est la meilleure façon de faire cela en Python?

108
Abdullah Jibaly

open et start sont des interpréteurs de commandes pour Mac OS/X et Windows, respectivement, pour ce faire.

Pour les appeler à partir de Python, vous pouvez utiliser subprocess module ou os.system().

Voici les considérations sur le paquet à utiliser:

  1. Vous pouvez les appeler via os.system, Qui fonctionne, mais ...

    Échappement: os.system Ne fonctionne qu'avec les noms de fichiers ne comportant aucun espace ni autre métacaractère Shell dans le chemin (par exemple, A:\abc\def\a.txt), ou alors il faut y échapper. Il y a shlex.quote Pour les systèmes de type Unix, mais rien de vraiment standard pour Windows. Peut-être aussi voir python, windows: analyse des lignes de commande avec shlex

    • MacOS/X: os.system("open " + shlex.quote(filename))
    • Windows: os.system("start " + filename) où proprement dit filename devrait également être échappé.
  2. Vous pouvez aussi les appeler via le module subprocess, mais ...

    Pour Python 2.7 et plus récent, utilisez simplement

    subprocess.check_call(['open', filename])
    

    Dans Python 3.5+, vous pouvez également utiliser le légèrement plus complexe mais aussi un peu plus polyvalent

    subprocess.run(['open', filename], check=True)
    

    Si vous devez être compatible jusqu’à Python 2.4, vous pouvez utiliser subprocess.call()] et implémenter votre propre vérification des erreurs:

    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
    

    Maintenant, quels sont les avantages d’utiliser subprocess?

    • Sécurité: En théorie, c'est plus sécurisé, mais en réalité, nous devons exécuter une ligne de commande d'une manière ou d'une autre; dans l'un ou l'autre environnement, nous avons besoin de l'environnement et des services pour interpréter, obtenir des chemins, etc. Dans aucun des deux cas, nous n’exécutons du texte arbitraire, il n’a donc pas de problème inhérent "mais vous pouvez taper 'filename ; rm -rf /'" Et if le nom du fichier peut être corrompu, l’utilisation de subprocess.call ne nous donne que peu de protection supplémentaire.
    • Traitement des erreurs: Cela ne nous permet plus de détecter les erreurs, nous dépendons toujours de retcode dans les deux cas; mais le fait de lever explicitement une exception en cas d'erreur vous aidera certainement à le signaler en cas d'échec (bien que, dans certains cas, une analyse rétrospective pourrait ne pas être plus utile que de simplement ignorer l'erreur).
    • Génère un sous-processus (non bloquant) : Il n'est pas nécessaire d'attendre le processus enfant, car nous sommes résolus par un problème à démarrer un processus séparé .

    A l'objection "Mais subprocess est préféré." Cependant, os.system() n'est pas obsolète, et constitue en quelque sorte l'outil le plus simple pour ce travail particulier. Conclusion: utiliser os.system() est donc aussi une réponse correcte.

    Un inconvénient marqué est que Windows start commande requiert vous devez passer Shell=True qui annule la plupart des avantages de l'utilisation de subprocess.

59
Charlie Martin

Utilisez le module subprocess disponible sur Python 2.4+, et non os.system()] _, afin que vous n'ayez pas à gérer l'échappement de 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))

Les doubles parenthèses sont dues au fait que subprocess.call() veut une séquence comme premier argument, nous utilisons donc un Tuple ici. Sur les systèmes Linux avec Gnome, il existe également une commande gnome-open Qui fait la même chose, mais xdg-open Est la norme Free Desktop Foundation et fonctionne sur les environnements de bureau Linux.

132
Nick

Je préfère:

os.startfile(path, 'open')

Notez que ce module prend en charge les noms de fichiers contenant des espaces dans leurs dossiers et leurs fichiers, par exemple.

A:\abc\folder with spaces\file with-spaces.txt

( python docs ) 'open' n'a pas besoin d'être ajouté (c'est la valeur par défaut). Les documents mentionnent spécifiquement qu'il s'agit d'un double-clic sur l'icône d'un fichier dans l'Explorateur Windows.

Cette solution est uniquement sous Windows.

36
DrBloodmoney

Juste pour être complet (ce n’était pas dans la question), xdg-open fera de même sous Linux.

32
dF.
import os
import subprocess

def click_on_file(filename):
    '''Open document with default application in Python.'''
    try:
        os.startfile(filename)
    except AttributeError:
        subprocess.call(['open', filename])
22
nosklo

Si vous devez utiliser une méthode heuristique, vous pouvez considérer webbrowser.
C'est une bibliothèque standard et malgré son nom, elle essaierait également d'ouvrir des fichiers:

Notez que sur certaines plates-formes, essayer d’ouvrir un nom de fichier en utilisant cette fonction peut fonctionner et démarrer le programme associé au système d’exploitation. Cependant, ceci n'est ni supporté ni portable. ( référence )

J'ai essayé ce code et cela a bien fonctionné sous Windows 7 et Ubuntu Natty:

import webbrowser
webbrowser.open("path_to_file")

Ce code fonctionne également très bien sous Windows XP Professional, avec Internet Explorer 8.

19
etuardu

Démarrer ne prend pas en charge les noms de chemin longs et les espaces. Vous devez le convertir en chemins compatibles 8.3.

import subprocess
import win32api

filename = "C:\\Documents and Settings\\user\\Desktop\file.avi"
filename_short = win32api.GetShortPathName(filename)

subprocess.Popen('start ' + filename_short, Shell=True )

Le fichier doit exister pour pouvoir fonctionner avec l'appel de l'API.

4
bFloch

Si vous voulez utiliser la méthode subprocess.call(), cela devrait ressembler à ceci sous Windows:

import subprocess
subprocess.call(('cmd', '/C', 'start', '', FILE_NAME))

Vous ne pouvez pas simplement utiliser:

subprocess.call(('start', FILE_NAME))

parce que startn’est pas un exécutable mais une commande du cmd.exe programme. Cela marche:

subprocess.call(('cmd', '/C', 'start', FILE_NAME))

mais seulement s'il n'y a pas d'espaces dans FILE_NAME.

Tandis que subprocess.call méthode encite les paramètres correctement, la commande start a une syntaxe plutôt étrange, où:

start notes.txt

fait autre chose que:

start "notes.txt"

La première chaîne entre guillemets doit définir le titre de la fenêtre. Pour que cela fonctionne avec des espaces, nous devons faire:

start "" "my notes.txt"

c'est ce que fait le code en haut.

4
Tomas Sedovic

Je suis assez tard pour le lot, mais voici une solution utilisant l’API Windows. Cela ouvre toujours l'application associée.

import ctypes

Shell32 = ctypes.windll.Shell32
file = 'somedocument.doc'

Shell32.ShellExecuteA(0,"open",file,0,0,5)

Beaucoup de constantes magiques. Le premier zéro est le hwnd du programme en cours. Peut être zéro. Les deux autres zéros sont des paramètres facultatifs (paramètres et répertoire). 5 == SW_SHOW, il spécifie comment exécuter l'application. Lisez le docs de l'API ShellExecute pour plus d'informations.

2
George

os.startfile (chemin, 'ouvrir') sous Windows est bon car, lorsqu'il existe des espaces dans le répertoire, os.system ('start', nom_du_ chemin) ne peut pas ouvrir l'application correctement et lorsque l'i18n existe dans le répertoire, os. Le système doit remplacer le code unicode par le codec de la console sous Windows.

1
BearPy

Sur les fenêtres 8.1, ci-dessous ont fonctionné alors que d’autres manières données avec subprocess.call échoue avec chemin contenant des espaces.

subprocess.call('cmd /c start "" "any file path with spaces"')

En utilisant ceci et les réponses d'autres avant, voici un code en ligne qui fonctionne sur plusieurs plates-formes.

import sys, os, subprocess
subprocess.call(('cmd /c start "" "'+ filepath +'"') if os.name is 'nt' else ('open' if sys.platform.startswith('darwin') else 'xdg-open', filepath))
0
Ch.Idea

Si vous souhaitez spécifier l'application avec laquelle ouvrir le fichier sous Mac OS X, utilisez ceci: os.system("open -a [app name] [file name]")

0
eppsilon

sur mac os vous pouvez appeler 'open'

import os
os.popen("open myfile.txt")

cela ouvrirait le fichier avec TextEdit, ou quelle que soit l'application définie par défaut pour ce type de fichier

0
lcvinny