HTTPConnection et barre de progression

HTTPConnection et barre de progression - Python - Programmation

Marsh Posté le 31-01-2005 à 10:35:44    

Je suis en train de développer un programme dont le but est d'identifier un fichier particulier sur le disque dur, d'en extraire certaines informations et d'envoyer ces données à un script php au moyen d'une requête POST.
 
J'utilise httplib pour me connecter au serveur web et construire la requête POST, avec les en-têtes et l'encodage qui vont bien. Je passe donc par l'objet HTTPConnection pour l'envoi, puis par HTTPResponse pour valider qu'il a été effectué correctement.
 
Jusqu'ici c'est parfait, mais j'aimerais afficher une barre de progression visuelle de l'envoi de la requête. En effet, la quantité de données peut être relativement importante, et j'aimerais informer l'utilisateur de la bonne progression de l'envoi.
 
Le problème, c'est que je ne sais pas de quelle façon je peux obtenir les informations sur la progression de l'envoi. J'ai regardé de près les classes mises en jeu:
- HTTPConnection ne propose pas de méthode ou d'attribut concernant les données déjà envoyées
- Socket.send() renvoie le nombre d'octets envoyés
 
Je pressents que si je veux pouvoir afficher une barre de progression je vais devoir me passer de HTTPConnection et d'opérer directement au niveau du socket.
A moins de dériver HTTPConnection et de modifier la bonne méthode pour gérer cette progression ?
 
Si quelqu'un a une idée à ajouter, une confirmation ou une infirmation de mes hypothèses je suis preneur.
Merci d'avance.


---------------
Loose Change Lies | Bars | Last.fm
Reply

Marsh Posté le 31-01-2005 à 10:35:44   

Reply

Marsh Posté le 02-02-2005 à 15:33:11    

Effectivement telle qu'est faite la classe HTTPConnection tu ne pourras pas faire grand chose, quand tu fais request() c'est la méthode sendall() du socket qui est utilisée et on ne peut rien faire avec si ce n'est espérer qu'elle ne se plante pas...
A la limite tu pourrais peut être essayer de créer une nouvelle classe dérivée de HTPPConnection dans laquelle tu redéfinis la méthode send. Au lieu d'envoyer tout d'un bloc on pourrait découper les données en blocs de 1024 octets et à chaque envoi réussi mettre à jour une variable. Il ne resterait alors qu'à lire cette variable à intervalles réguliers pour voir où on en est.
Je n'ai pas testé mais c'est ce qui me paraitrait le plus simple à mettre en oeuvre, ça évite de devoir réimplémenter tout le protocole HTTP au niveau socket...

Reply

Marsh Posté le 02-02-2005 à 16:32:26    

Voui c'est un peu ce que je me suis dit, je pense que je vais me retourner vers cette solution, parce qu'effectivement sinon c'est assez galère :)
 
Merci !


---------------
Loose Change Lies | Bars | Last.fm
Reply

Marsh Posté le 03-02-2005 à 13:55:31    

Pour plus de flexibilité, j'ai implémenté une classe HTTPProgressConnection qui dérive de HTTPConnection en redéfinissant sa commande send()
 
Je fais l'envoi en passant par socket.send() au lieu de socket.sendall(), et j'ai ajouté la possibilité de mettre un callback à chaque appel de socket.send() pour renvoyer le nombre d'octets déjà envoyés et le nombre total d'octets.
 

Code :
  1. import httplib, urllib
  2. class HTTPProgressConnection(httplib.HTTPConnection):
  3. def __init__(self, host, port=None, strict=None):
  4.  httplib.HTTPConnection.__init__(self, host, port, strict)
  5.  self.progress_callback = None
  6.  self.send_buffer_size = 1024
  7. def send(self, str):
  8.  """Send `str' to the server and calls self.progress_callback() when data is actually sent"""
  9.  if self.sock is None:
  10.   if self.auto_open:
  11.    self.connect()
  12.   else:
  13.    raise NotConnected()
  14.  if self.debuglevel > 0:
  15.   print "send:", repr(str)
  16.  try:
  17.   # Start of modification to the original HTTPConnection.send()
  18.   # Set the callback
  19.   if callable(self.progress_callback):
  20.    callback = self.progress_callback
  21.   else:
  22.    callback = lambda c,t: 0
  23.   total_bytecount = 0
  24.   total_size = len(str)
  25.   while total_bytecount < total_size:
  26.    total_bytecount += self.sock.send(str[total_bytecount:self.send_buffer_size])
  27.    callback(total_bitecount, total_size)
  28.   # End of the modification or the original HTTPConnection.send()
  29.  except socket.error, v:
  30.   if v[0] == 32:      # Broken pipe
  31.    self.close()
  32.   raise
  33. if __name__ == "__main__":
  34. def simple_callback(current, total):
  35.  print "%(current)d / %(total)" % (current, total)
  36. params = urllib.urlencode({'q': 'python c\'est bon !'})
  37. hpc = HTTPProgressConnection('www.google.fr', 80)
  38. hpc.progress_callback = simple_callback
  39. print 'hpc.request():'
  40. hpc.request('GET', '/search', params)


 
Le constructeur de HTTPProgressConnection est le même que celui de HTTPConnection, et définit deux attributs supplémentaires:
- progress_callback, qui est la fonction de callback à appeler lors de chaque envoi de données, et qui doit recevoir deux arguments
- send_buffer_size, qui est un nom trompeur (à changer) qui définit la taille des données envoyées par appel à socket.send()
 
J'ai pas pu tester en l'état parce que cette classe ne supporte pas les proxies, et que j'en ai un à ma boîte.


---------------
Loose Change Lies | Bars | Last.fm
Reply

Marsh Posté le 04-02-2005 à 00:18:29    

Après tests, il savère qu'il y avait un bug idiot:
 
A la ligne 29, il faut remplacer:
 

Code :
  1. total_bytecount += self.sock.send(str[total_bytecount:self.send_buffer_size])


Par  

Code :
  1. total_bytecount += self.sock.send(str[total_bytecount:total_bytecount + self.send_buffer_size])


 
Sinon évidemment ça risque pas de marcher des masses dès lors qu'il y a plus de données que la taille d'envoi [:huit]


---------------
Loose Change Lies | Bars | Last.fm
Reply

Marsh Posté le 04-02-2005 à 17:43:04    

Joli, c'est en voyant ça qu'on se dit que c'est bien le Python...
Par contre pour le proxy tu risques de te faire chier, j'avais commencé à regarder pour le boulot et je n'ai pas réussi à faire fonctionner pour les proxies avec authentification. Certes je n'avais pas trop recherché mais bon...

Reply

Marsh Posté le 07-02-2005 à 10:42:21    

De ce que j'ai pu voir, les proxies sont gérés avec urllib et urllib2, la seconde ayant une interface un peu plus pratique d'utilisation avec la classe request. Pour l'authentification y'a pas mal de choses, mais j'ai pas le temps ni l'opportunité de m'y plonger.


---------------
Loose Change Lies | Bars | Last.fm
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed