Sam & Max » file http://sametmax.com Du code, du cul Sat, 07 Nov 2015 10:56:13 +0000 en-US hourly 1 http://wordpress.org/?v=4.1 Invalid cross-device link 3 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
J’adore les context managers Python http://sametmax.com/jadore-les-context-managers-python/ http://sametmax.com/jadore-les-context-managers-python/#comments Tue, 24 Jul 2012 15:15:53 +0000 http://sametmax.com/?p=1296 En Python il y a plein de trucs pas du tout indispensables: les metaclasses, les décorateurs, les listes en intentions… Elles sont là uniquement pour rendre le langage plus agréable à l’usage, mais on pourrait faire sans. Les context managers en font partie. Loin de moi l’idée de faire un tuto ce matin sur les context managers, mais j’ai juste l’envie d’énoncer tout haut mon amour cette fonctionnalité.

Prenez un model Django Media: vous transcodez ce media, vous faites souvent des opérations dans son dossier. Il faut s’assurer que ça marche. Et quand ça foire, il faut s’assurer que l’on a bien nettoyé le répertoire de travail.

Hop:

class Media(models.Model):
 
    [...]
 
    @contextmanager
    def in_dir(self, delete_on_error=False):
        # si vous ne comprenez pas ce code, ne vous en faites pas,
        # c'est du Python avancé
        try:
            os.makedirs(self.dir)
        except (OSError, IOError) as e:
            pass
 
        try:
            yield self.dir
        except:
            if delete_on_error:
                shutil.rmtree(self.dir)
            raise

Et voilà, Max dans ses scripts de transcoding magiques n’a pas à se poser de question. Il a juste à faire:

with media.in_dir(delete_on_error=True) as d:
    # faire des trucs avec le dossier dont le chemin est dans "d"

Le chemin spécifique pour ce média est garanti d’exister.

Si il y a une exception, le dossier est garanti d’être nettoyé.

C’est simple, c’est propre, c’est beau. J’aime.

]]>
http://sametmax.com/jadore-les-context-managers-python/feed/ 0