os – Sam & Max http://sametmax.com Du code, du cul Wed, 23 Dec 2020 13:35:02 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Ouvrir un fichier avec le bon programme en Python http://sametmax.com/ouvrir-un-fichier-avec-le-bon-programme-en-python/ http://sametmax.com/ouvrir-un-fichier-avec-le-bon-programme-en-python/#comments Thu, 17 Oct 2013 10:09:59 +0000 http://sametmax.com/?p=7469 Votre logiciel doit permettre d’ouvrir un fichier avec un programme externe. Oui mais lequel ?

Les OS ont des réglages par défaut pour chaque type de fichier, et on peut demander “ouvrir le prog pour ce type de fichier par défaut”. Par exemple, moi, si je demande d’ouvrir un fichier vidéo, je m’attend à ce que VLC soit lancé.

Voilà comment faire ça en Python :

import subprocess
import sys
import os

def run_file(path):

    # Pas de EAFP cette fois puisqu'on est dans un process externe,
    # on ne peut pas gérer l'exception aussi facilement, donc on fait
    # des checks essentiels avant.

    # Vérifier que le fichier existe
    if not os.path.exists(path):
        raise IOError('No such file: %s' % path)

    # On a accès en lecture ?
    if hasattr(os, 'access') and not os.access(path, os.R_OK):
        raise IOError('Cannot access file: %s' % path)

    # Lancer le bon programme pour le bon OS :

    if hasattr(os, 'startfile'): # Windows
        # Startfile est très limité sous Windows, on ne pourra pas savoir
        # si il y a eu une erreu
        proc = os.startfile(path)

    elif sys.platform.startswith('linux'): # Linux:
        proc = subprocess.Popen(['xdg-open', path], 
                                 # on capture stdin et out pour rendre le 
                                 # tout non bloquant
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    elif sys.platform == 'darwin': # Mac:
        proc = subprocess.Popen(['open', '--', path], 
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    else:
        raise NotImplementedError(
            "Your `%s` isn't a supported operatin system`." % sys.platform)

    # Proc sera toujours None sous Windows. Sous les autres OS, il permet de
    # récupérer le status code du programme, and lire / ecrire sur stdin et out
    return proc

C’était le petit snippet sympas du jour !

P.S : si quelqu’un utilise BDSM BSD ou Solaris, je veux bien qu’il complète le snippet.

]]>
http://sametmax.com/ouvrir-un-fichier-avec-le-bon-programme-en-python/feed/ 18 7469
Invalid cross-device link http://sametmax.com/invalid-cross-device-link/ http://sametmax.com/invalid-cross-device-link/#comments Tue, 09 Apr 2013 10:19:57 +0000 http://sametmax.com/?p=5652 Les erreurs d’upload de fichier, c’est 99% de problèmes de droit d’accès et d’espace disque. Mais de temps à autres, on tombe sur des petites saloperies bien vicelardes comme ce code anodin :

os.rename(uploaded_tmp_file, destination)

Ce snippet, comme vous l’aurez compris, prend simplement un fichier qui vient d’être uploadé et le déplace vers un autre dossier où il sera traité, chouchouté, encodé, et mis en ligne.

Sauf que la ligne en question nous a valu un cryptique :

IOError: Invalid cross-device link

PDB nous confirme le merdier, même en le faisant à la main. Pourtant la commande bash MV fait le déplacement du fichier sans problème.

User / group ? Checked.

Permission en lecture écriture ? Checked.

SEL linux ? Désactivé depuis longtemps.

Quid alors ?

Les archives de la mailling list de Python nous offre une réponse à la question, que je vous traduis :

mv est un programme étonnamment complexe, tandis que os.rename est un wrapper autour de rename(2) qui est probablement documenté sur ton système comme retournant EXDEV dans ces circonstances.

os.xxx est généralement une surcouche assez fine autour de ce que ton OS fournit, et en hérite toutes les limites. Pour certains actions, os.shutil fournit quelque chose qui se situe entre os.xxx et os.system(“xxx”) en terme de complexité et de capacité.

Je l’ai traduis en français, maintenant je vous la refais en langage humain : os.rename ne fait vaguement qu’appeler la commande rename, qui n’est pas très puissante, et notamment qui est incapable de gérer un déplacement de fichier d’une partition à une autre. Or dans notre cas, notre dossier temporaire était sur une partition séparée pour des raisons de perfs.

La solution est d’utiliser shutil, un module un peu plus lent, mais surtout de plus haut niveau qui se charge des détails comme la nature et l’origine du fichier et de sa destination.

Bref, la solution est tout simplement de faire :

shutil.move(uploaded_tmp_file, destination)

Tout ça pour ça, oui, mais c’est ce qui arrive quand une abstraction ne fait plus son boulot dans un langage de haut niveau où on a l’habitude que tout soit automatisé.

]]>
http://sametmax.com/invalid-cross-device-link/feed/ 3 5652