Sam & Max » shutil 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