Beaucoup d'entre vous sont certainement en période d'apprentissage de Python (comme moi), et à cela rien de plus normal, car Python nous offre énormément d'outils très performants pour développer !
Dans ce tutoriel, je vais vous parler d'un module en particulier, ftplib.
Si vous utilisez un client FTP (ce dernier étant un protocole, à l'instar du HTTP par exemple) tel que Filezilla, j'ai le plaisir de vous dire que vous pourrez faire la même chose (enfin presque :-° ) après la lecture de mon tutoriel ! À ceci près que vous le ferez en console et non en fenêtre. :p Par la suite, ce serait un bon exercice d'adapter le script à un « mode » fenêtre avec PyQt, PyGTK, etc.
Avant toute programmation, je tiens à préciser plusieurs petites choses.
Tout d'abord, sachez que je ne suis pas un « pro » de Python, il y a donc certainement une meilleure façon de coder que celle donnée ici. Dans ce tutoriel, vous apprenez tout d'abord à vous servir du module, et non à coder.
D'ailleurs, je dois vous signaler que si vous n'avez pas lu le tutoriel rédigé par Gérard Swinnen (ou un équivalent), vous ne pourrez pas suivre le reste. Je pense que les dix premiers chapitres suffiront, le reste n'étant pas utilisé dans mon cours.
Bon, maintenant, je vais essayer de vous donner envie de lire la suite, en vous donnant la liste des choses que vous saurez faire à la fin de votre lecture :
se connecter à un serveur FTP ;
envoyer un fichier sur le serveur ;
créer un dossier ;
renommer un fichier ou un dossier ;
supprimer un fichier ou un dossier ;
changer le répertoire courant ;
lister tous les fichiers et dossiers d'un répertoire ;
envoyer une commande au serveur (sans passer par des fonctions Python) ;
recevoir les messages renvoyés par le serveur après chaque action.
Comme vous pouvez le constater, la liste est longue !
À la fin du tutoriel, vous aurez un script qui permettra d'exécuter toutes ces commandes, mais il ne vous sera donné que vers la fin. Quand j'expliquerai comment faire telle ou telle action, je ne vous donnerai que le strict minimum en code.
Dans cette partie, je vous expliquerai en détail comment on utilise la fonction N ou Y.
J'ai décidé d'effectuer cela par "mini-chapitre", c'est-à-dire que chaque fonction aura son titre. :)
Grâce à cette mise en page, ce tuto vous sera utile comme référence lorsque vous coderez. ;)
La connexion
Cette étape est la plus importante, car toutes les autres découlent de la connexion !
Rassurez-vous, son utilisation est on ne peut plus simple. :)
host = "votre_host.com" # adresse du serveur FTP
user = "votre_pseudo" # votre identifiant
password = "votre password" # votre mot de passe
connect = ftp.ftplib(host,user,password) # on se connecte
Je ne vais pas détailler ce code, tout est dans les commentaires. :)
Déconnexion
Étape tout aussi importante, la déconnexion. À vrai dire, théoriquement, si vous fermez la console, la connexion se ferme. Mais dans de gros scripts, il vaut mieux la fermer. Un inconvénient tout de même : une fois la connexion fermée, on ne peut plus la rouvrir !
connect.quit() # où "connect" est le nom de la variable dans laquelle vous avez déclaré la connexion !
Envoyer un fichier
Cette commande est certainement l'une des plus utilisées ! Encore une fois, elle est très simple.
Voici les lignes à insérer pour envoyer un fichier :
fichier = "C:\Python_exercices\ftp.py"
file = open(fichier, 'rb') # ici, j'ouvre le fichier ftp.py
connect.storbinary('STOR '+fichier, file) # ici (où connect est encore la variable de la connexion), j'indique le fichier à envoyer
file.close() # on ferme le fichier
Comme vous le voyez, à la 3e ligne du code, on met 'STOR'+fichier.
Pourquoi on met ça ? o_O
Bonne question. Sachez que 'STOR' est une commande FTP (et non Python). Ici, on indique au serveur quelle action on va effectuer, c'est très important. J'ai effectué juste derrière une concaténation ; à la fin, cela donnera ceci : STOR C:\Python_exercices\ftp.py.
État de la connexion
Lorsque l'on se connecte au serveur, il nous renvoie un message. Avec la fonction que je vais donner ci-dessous, nous allons récupérer ce message pour éventuellement l'afficher après. ;)
etat = connect.getwelcome() # grâce à la fonction getwelcome(), on récupère le "message de bienvenue"
print "Etat : ", etat # ici, on l'affiche, cette ligne est facultative mais si vous ne l'affichez pas, c'est bête :p
Lister les fichiers & dossiers du répertoire
Après plusieurs actions effectuées sur le serveur, vous avez envie de voir si tout s'est bien déroulé ? Pour cela, il vous suffira de lister le répertoire, avec la fonction dir().
rep = connect.dir() # on récupère le listing
print rep # on l'affiche dans la console
Personnellement, je vous conseille d'afficher le listing du répertoire après chaque action de renommage, d'effaçage, etc. Cela vous permettra de voir si tout s'est bien passé. ;)
Renommer un fichier ou un dossier
Parmi les actions que j'ai citées dans la première partie, il y avait "Renommer un fichier ou un dossier". Ici, je vous explique comment le faire. :)
renommer = raw_input('Tapez le nom du fichier / dossier à renommer : ') # ici, vous devez entrer le nom du fichier à renommer, par exemple fichier.txt ou le nom du dossier sans les /
renommer_en = raw_input('Le renommer en : ') # le nom de sortie, vous pouvez aussi changer l'extension
rename = connect.rename(renommer, renommer_en) # maintenant, on effectue vraiment l'action
J'ai rajouté deux raw_input() afin de faciliter votre travail dans la console, mais la fonction pour renommer tient sur une seule ligne.
Effacer un fichier
Après "renommer un fichier", il y a évidemment "effacer un fichier". :p Ici, c'est encore plus simple (si c'est possible o_O ), il faut juste indiquer le nom !
effacer = raw_input('Tapez le nom du fichier à effacer : ') # vous indiquez dans la console le fichier, ex. : fichier.py
delete = connect.delete(effacer) # là, c'est la fonction en elle-même
Créer un répertoire
Cela ne sert à rien d'expliquer en trente lignes, je vous laisse lire le code. :)
rep = raw_input('Tapez le nom du répertoire à créer : ') # entrez le nom du répertoire, sans les slash ( / )
repertoire = connect.mkd(rep) # la fonction pour le créer, "mkd()"
Supprimer un répertoire
Pour supprimer un dossier, ce n'est pas la même fonction que pour supprimer un fichier. Ça peut paraître logique, mais je tiens à le signaler. Voici le code :
supprimer = raw_input('Tapez le nom du répertoire à supprimer : ') # entrez le nom du dossier
delete_dir = connect.rmd(supprimer) # la fonction rmd supprime le dossier
Envoyer une fonction FTP au serveur
Quand vous ouvrez votre client FTP (par exemple Filezilla), il a une partie qui concerne les commandes envoyées au serveur (ce n'est peut-être pas présent sur tous les clients FTP). Lorsque vous changez de répertoire, vous pouvez voir des lignes défiler, avec des noms bizarres...
Et c'est quoi, ces noms ?
Je ne vous le dirai pas, nananèreuh. :-° Ce sont des commandes FTP ! Juste que là, Python nous servait d'intermédiaire entre le serveur et nous. Mais qu'envoie Python au serveur ? Pas des fonctions Python, quand même ? o_O Eh bien non, tout simplement des commandes, c'est-à-dire des noms barbares du type "CWD".
Ici, je vais vous décrire la marche à suivre pour en envoyer, mais point vous lister toutes les commandes existantes !
commande = raw_input('Tapez la commande à effectuer : ') # entrez la commande à effectuer
resultat = connect.sendcmd(commande) # on envoie la commande au serveur : si elle n'est pas bonne, Python plantera
Je vous donne juste un exemple de commande FTP, qui vous servira forcément : CWD rep. Elle sert à changer le répertoire. Par exemple, pour aller au répertoire "Admin" de votre site :
connect.sendcmd('CWD Admin')
Recevoir la réponse du serveur suite à une action
Rassurez-vous, rien de plus simple à faire. :) Imaginons que vous avez cette ligne en python :
rename = connect.rename('Admin', 'Administration') # action de renommage
Il vous suffira d'afficher la variable rename :
rename = connect.rename('Admin', 'Administration') # action de renommage
print rename # on affiche la réponse du serveur
Arrêter le transfert d'un fichier
Il existe une fonction (incluse au module ftplib) qui permet de stopper (ou « d'avorter ») le transfert d'un fichier. Je vous donne la fonction, mais je vous indique que dans la partie suivante, dans le script que nous allons réaliser, elle n'y sera pas. En effet, lors du traitement d'une commande (donc ici, l'envoi d'un fichier), le script ne nous permet pas de renvoyer une autre commande ; du coup, mieux vaut fermer la fenêtre de la console, cela aura le même effet. :D
connect.abort() # abort() avorte le transfert
C'est la fin de cette partie ! Dans la dernière partie (c'est-à-dire la suivante), je vais vous montrer comment faire pour mettre nos connaissances à profit en créant un script Python contenant toutes les fonctions vues ensemble. :)
Dans cette dernière partie, je vous propose de faire un petit programme et toutes les fonctions que l'on a vues y seront.
Dans ce script, nous allons utiliser une notion importante, les décorateurs.
En gros, grâce à eux, vous pourrez appeler une fonction à l'initialisation d'une autre. C'est un peu compliqué à expliquer ici : je préfère vous donner un lien vers un tutoriel traitant de ce sujet : Décorateurs.
Bon : maintenant, passons au vif du sujet. Nous allons créer une fonction pour chaque action possible, et auxiliairement une aide pour chaque fonction. ;)
À l'entrée des commandes dans la console, on effectuera deux tests principaux :
si la fonction existe ;
et si oui, si l'on a précisé des paramètres.
Pour cela, on utilisera évidemment (c'est tellement plus simple :p ) try, except et compagnie.
Voici la bête :
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# ftp.py
# FTP CLI interface
#
# Copyright (C) 2007 Pierre "delroth" Bourdon <[email protected]>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import ftplib as ftp # on importe le module et on la renomme juste pour le script en "ftp"
commands = {} # on crée le dictionnaire qui contiendra toutes les commandes & descriptions
def connection(value=None):
if value == None:
return getattr(connection, 'value', None)
else:
connection.value = value
return value
def ftpcommand(nom_court, description): # fonction pour ajouter la fonction au dictionnaire commands
def decorator(function):
global commands # on n'oublie pas de mettre le dico commands global, sinon ça va en redéfinir un
commands[nom_court] = (function, description) # on ajoute au dictionnaire
return function
return decorator
@ftpcommand("help", "Affiche l'aide des commandes") # ici on appelle le décorateur : il va s'occuper d'ajouter la fonction help avec sa description au dictionnaire commands
def help(): # définition de la commande, juste après @ftpcommand car ON EST OBLIGÉS
global commands
keys = commands.keys() # on récupère les clés == fonctions dans notre cas
keys.sort() # on trie par ordre alphabétique :)
for i in keys:
print i+" : "+commands[i][1] # on affiche le nom de la fonction et sa description
@ftpcommand("connect", "Se connecte au serveur. Syntaxe: connect <host> <user> <password>")
def connect(host, user, password):
connection(ftp.FTP(host, user, password))
@ftpcommand("ls", "Liste le contenu du répertoire actuel")
def ls():
print connection().dir() # on affiche le listing du répertoire
@ftpcommand("deco", "Se déconnecte du serveur. Syntaxe: deco")
def deco():
connection().quit() # la déconnexion avec quit()
@ftpcommand("envoi", "Envoie un fichier au serveur. Syntaxe: envoi <adresse_fichier>")
def envoi(adresse_fichier):
fichier = adresse_fichier
file = open(fichier, 'rb') # on ouvre le fichier en mode "read-binary"
connection().storbinary('STOR '+fichier, file) # envoi
file.close() # fermeture du fichier
@ftpcommand("rename", "Renomme un fichier. Syntaxe: rename <avant> <apres>")
def rename(avant, apres):
renommer, renommer_en = avant, apres
rename = connection().rename(renommer, renommer_en) # on renomme
@ftpcommand("efface", "Efface un fichier. Syntaxe : efface <fichier>")
def efface(fichier):
effacer = fichier
delete = connection().delete(effacer) # on efface
@ftpcommand("creer_rep", "Crée un répertoire (dossier). Syntaxe : creer_rep <nom>")
def creer_rep(nom):
rep = nom
repertoire = connection().mkd(rep) # on crée le répertoire
@ftpcommand("sup_rep", "Supprimer un répertoire (dossier). Syntaxe : sup_rep <nom>")
def sup_rep(nom):
supprimer = nom
delete_dir = connection().rmd(supprimer) # on supprime le répertoire
@ftpcommand("cmd", "Envoie une commande au serveur. Syntaxe: cmd <commande>")
def cmd(commande):
resultat = connection().sendcmd(commande) # on envoi la commande
# un petit message à propos de la license du script :)
welcome = '''ftp.py version 1.0, Copyright (C) 2007
ftp.py comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
welcome to redistribute it under certain conditions; see the GNU General Public
License for more details: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html'''
def main():
global commands
print welcome # affichage du message ci-dessus
def command_to_argv(cmd):
argv = cmd.split(' ') # on met dans une liste les différents arguments
argv_size = len(argv) # on compte le nombre de paramètres
i = 0 # on initialise le compteur
while i < argv_size:
if argv[i].endswith('\\') and i + 1 != argv_size: # si c'est un nom de fichier du type : test\ 1.py
argv[i] = argv[i][:-1] + " " + argv[i + 1] # on ajoute le "1.py" à "test", ce qui fait "test 1.py"
del argv[i + 1]
argv_size -= 1
i += 1 # on incrémente le compteur
return argv # on retourne les arguments
while True: # boucle infinie, il va encore falloir utiliser break pour en sortir
try: cmd = command_to_argv(raw_input('> ')) # si la commande entrée provoque une erreur...
except EOFError: return 0 # on quitte la boucle
except KeyboardInterrupt: return 0 # on quitte la boucle
cmdname, args = cmd[0], cmd[1:] # cmdname = fonction appelée, args = arguments
if not cmdname in commands.keys(): # si la fonction appelée n'existe pas dans le script
print "Erreur: '%s' commande incorrecte." % cmdname # on affiche un message d'erreur
continue
try:
commands[cmdname][0](*args)
except TypeError:
print "Erreur: mauvais nombre d'arguments pour '%s' command." % cmdname
except AttributeError:
print "Erreur : vous n'êtes pas connecté !"
return 0
import sys
if __name__ == "__main__": sys.exit(main()) # si le script est utilisé comme un module, on n'exécute pas le script
Nous voici à la fin de ce tuto... déjà ! Dans ce tutoriel, j'ai mis à disposition toutes mes connaissances sur ce module, et j'espère qu'elles vous conviendront. :)
Je tiens à remercier delroth qui a refait mon exemple d'utilisation dans la dernière partie (mais j'ai quand même écrit les commentaires :) ). Grâce à lui, vous avez un code qui va beaucoup mieux fonctionner. :)
Théoriquement, vous savez dorénavant utiliser cette librairie ! En cas de trou de mémoire, vous pouvez venir lire la partie 2 du tutoriel qui liste toutes les fonctions principales.