J'essaie de copier un fichier avec pathlib
import pathlib
import shutil
my_file=pathlib.Path('/etc/hosts')
to_file=pathlib.Path('/tmp/foo')
shutil.copy(my_file, to_file)
Je reçois cette exception:
/home/foo_egs_d/bin/python /home/foo_egs_d/src/test-pathlib-copy.py
Traceback (most recent call last):
File "/home/foo_egs_d/src/test-pathlib-copy.py", line 6, in <module>
shutil.copy(my_file, to_file)
File "/usr/lib/python2.7/shutil.py", line 117, in copy
if os.path.isdir(dst):
File "/home/foo_egs_d/lib/python2.7/genericpath.py", line 41, in isdir
st = os.stat(s)
TypeError: coercing to Unicode: need string or buffer, PosixPath found
Process finished with exit code
... comment copier un fichier avec pathlib dans Python 2.7?
Et alors?
import pathlib
import shutil
my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')
shutil.copy(str(my_file), str(to_file))
Le problème est que pathlib.Path
Crée un objet PosixPath
si vous utilisez Unix/Linux, WindowsPath
si vous utilisez Microsoft Windows.
Mais shutil.copy()
a besoin d'une chaîne comme arguments. Il suffit donc d'utiliser str()
ici, lorsque vous utilisez la fonction str()
sur un objet Path
, il retournera le chemin d'origine.
La raison pour laquelle shutil.copy()
ne fonctionne pas est que vous n'utilisez pas la dernière version de Python, Python 3.6 shutil.copy()
can handle Path
objets (ou sous-classes de ceux-ci). Que pour les anciennes versions de Python cela génère une erreur, c'est parce que les implémentations de shutil
attendent des arguments de chaîne pour copy
, et non les arguments de type pathlib.Path
.
Ce que vous voulez réellement pouvoir écrire, c'est:
my_file.copy(to_file)
Vous pouvez sous-classer Path pour inclure une telle méthode et adapter la création de my_file
. Je trouve plus facile de simplement le greffer/patch-singe/duck-punch sur l'existant pathlib.Path
from pathlib import Path
def _copy(self, target):
import shutil
assert self.is_file()
shutil.copy(str(self), str(target)) # str() only there for Python < (3, 6)
Path.copy = _copy
Vous pouvez placer ce code où vous le souhaitez, tant qu'il est exécuté avant d'appeler la méthode .copy
Sur l'une des instances Path
. L'argument de .copy()
peut être un fichier ou un répertoire.
Depuis Python 3.5, sans importer shutil
, vous pouvez faire:
_from pathlib import Path
dest = Path('dest')
src = Path('src')
dest.write_bytes(src.read_bytes()) #for binary files
dest.write_text(src.read_text()) #for text files
_
Pour Python 2.7, _pathlib2
_ fournit le _read_bytes
_, _read_text
_, _write_bytes
_ et _write_text
_ méthodes.
Le fichier sera chargé en mémoire, cette méthode ne convient donc pas aux fichiers plus grands que la mémoire disponible de la machine.
Selon les commentaires, on peut utiliser _write_bytes
_ et _read_bytes
_ pour copier des fichiers texte, mais si vous devez gérer l'encodage au moment de la copie _write_text
_ an _read_text
_ présenter l'avantage de deux paramètres supplémentaires:
encoding
est le nom de l'encodage utilisé pour décoder ou encoder le fichiererrors
est une chaîne facultative qui spécifie comment les erreurs d'encodage et de décodage doivent être traitéesIls ont tous deux la même signification que dans open()
.
Comment shutil
a été converti pour accepter les objets pathlib.Path
Dans Python 3.6
Comme mentionné sur https://stackoverflow.com/a/40319071/895245 shutil in Python 3.6 peut prendre des objets pathlib.Path
.
Comme cela semblait assez magique, j'ai décidé d'étudier un peu comment il était implémenté pour voir si je serais en mesure de réutiliser cette magie dans mes propres cours.
L'amélioration est le résultat du PEP 519: https://www.python.org/dev/peps/pep-0519/
Cela généralisait beaucoup de fonctionnalités stdlib, et la documentation n'était pas mise à jour de manière conséquente, y compris la plupart de shutil
qui à partir de 3.7 seuls les documents supportent dans une seule fonction . Bienvenue aux joies de la frappe dynamique.
Là où cela est documenté, le stlib renvoie au glossaire des "objets de type chemin": https://docs.python.org/3/glossary.html#term-path-like-object
Un objet représentant un chemin d'accès au système de fichiers. Un objet semblable à un chemin est soit un objet str ou bytes représentant un chemin, soit un objet implémentant le protocole os.PathLike. Un objet qui prend en charge le protocole os.PathLike peut être converti en chemin de système de fichiers str ou bytes en appelant la fonction os.fspath (); os.fsdecode () et os.fsencode () peuvent être utilisés pour garantir un résultat str ou octets à la place, respectivement. Introduit par PEP 519.
et qui renvoie ensuite à la documentation de os.PathLike
: https://docs.python.org/3/glossary.html#term-path-like-object
Une classe de base abstraite pour des objets représentant un chemin de système de fichiers, par ex. pathlib.PurePath.
Nouveau dans la version 3.6.
abstractmethod __fspath__()
Renvoie la représentation du chemin d'accès au système de fichiers de l'objet.
La méthode ne doit renvoyer qu'un objet str ou bytes, la préférence étant pour str.
Les principaux engagements de mise en œuvre semblent être:
Modules/posixmodule.c
__fspath__
À pathlib.PurePath
Si vous souhaitez implémenter vos propres classes de type chemin, vous pouvez le faire comme:
#!/usr/bin/env python3
class MyPath:
def __init__(self, path):
self.path = path
def __fspath__(self):
return self.path
with open(MyPath('f'), 'w'):
pass
Testé dans Python 3.6.7, Ubuntu 18.10.
Vous pouvez utiliser pathlib renommer la méthode au lieu de shutil.move ().
import pathlib
my_file = pathlib.Path('/etc/hosts')
to_file = pathlib.Path('/tmp/foo')
my_file.rename(to_file)