Mercurial > boomslang
view pyweek-upload.py @ 626:cc1085432faf pyntnclick
Rip out more CursorWidget
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Sat, 11 Feb 2012 22:06:23 +0200 |
parents | d1b86d5849a0 |
children |
line wrap: on
line source
''' Upload script specifically engineered for the PyWeek challenge. Handles authentication and gives upload progress feedback. ''' import cStringIO import getopt import httplib import os import socket import sys import time class Upload: def __init__(self, filename): self.filename = filename boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' sep_boundary = '\n--' + boundary end_boundary = sep_boundary + '--' def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary): '''Take the mapping of data and construct the body of a multipart/form-data message with it using the indicated boundaries. ''' ret = cStringIO.StringIO() for key, value in data.items(): # handle multiple entries for the same name if type(value) != type([]): value = [value] for value in value: ret.write(sep_boundary) if isinstance(value, Upload): ret.write('\nContent-Disposition: form-data; name="%s"' % key) filename = os.path.basename(value.filename) ret.write('; filename="%s"\n\n' % filename) value = open(os.path.join(value.filename), "rb").read() else: ret.write('\nContent-Disposition: form-data; name="%s"' % key) ret.write("\n\n") value = str(value) ret.write(str(value)) if value and value[-1] == '\r': ret.write('\n') # write an extra newline ret.write(end_boundary) return ret.getvalue() class Progress: def __init__(self, info, data): self.info = info self.tosend = len(data) self.total = self.tosend / 1024 self.data = cStringIO.StringIO(data) self.start = self.now = time.time() self.sent = 0 self.num = 0 self.stepsize = self.total / 100 or 1 self.steptimes = [] self.display() def __iter__(self): return self def next(self): self.num += 1 if self.sent >= self.tosend: print self.info, 'done', ' ' * (75 - len(self.info) - 6) sys.stdout.flush() raise StopIteration chunk = self.data.read(1024) self.sent += len(chunk) #print (self.num, self.stepsize, self.total, self.sent, self.tosend) if self.num % self.stepsize: return chunk self.display() return chunk def display(self): # figure how long we've spent - guess how long to go now = time.time() steptime = now - self.now self.steptimes.insert(0, steptime) if len(self.steptimes) > 5: self.steptimes.pop() steptime = sum(self.steptimes) / len(self.steptimes) self.now = now eta = steptime * ((self.total - self.num) / self.stepsize) # tell it like it is (or might be) if now - self.start > 3: M = eta / 60 H = M / 60 M = M % 60 S = eta % 60 if self.total: s = '%s %2d%% (ETA %02d:%02d:%02d)' % (self.info, self.num * 100. / self.total, H, M, S) else: s = '%s 0%% (ETA %02d:%02d:%02d)' % (self.info, H, M, S) elif self.total: s = '%s %2d%%' % (self.info, self.num * 100. / self.total) else: s = '%s %d done' % (self.info, self.num) sys.stdout.write(s + ' ' * (75 - len(s)) + '\r') sys.stdout.flush() class progressHTTPConnection(httplib.HTTPConnection): def progress_send(self, str): """Send `str' to the server.""" if self.sock is None: self.connect() p = Progress('Uploading', str) for chunk in p: sent = 0 while sent != len(chunk): try: sent += self.sock.send(chunk) except socket.error, v: if v[0] == 32: # Broken pipe self.close() raise p.display() class progressHTTP(httplib.HTTP): _connection_class = progressHTTPConnection def _setup(self, conn): httplib.HTTP._setup(self, conn) self.progress_send = self._conn.progress_send def http_request(data, server, port, url): h = progressHTTP(server, port) data = mimeEncode(data) h.putrequest('POST', url) h.putheader('Content-type', 'multipart/form-data; boundary=%s' % boundary) h.putheader('Content-length', str(len(data))) h.putheader('Host', server) h.endheaders() h.progress_send(data) errcode, errmsg, headers = h.getreply() f = h.getfile() response = f.read().strip() f.close() print '%s %s' % (errcode, errmsg) if response: print response def usage(): print '''This program is to be used to upload files to the PyWeek system. You may use it to upload screenshots or code submissions. REQUIRED ARGUMENTS: -u username -p password -d description of file -c file to upload -e entry short name OPTIONAL ARGUMENTS: -s file is a screenshot -f file is FINAL submission -h override default host name (www.pyweek.org) -P override default host port (80) In order to qualify for judging at the end of the challenge, you MUST upload your source and check the "Final Submission" checkbox. ''' if __name__ == '__main__': try: optlist, args = getopt.getopt(sys.argv[1:], 'e:u:p:sfd:h:P:c:') except getopt.GetoptError, message: print message usage() sys.exit(1) host = 'www.pyweek.org' port = 80 data = dict(version=2) optional = {} url = None for opt, arg in optlist: if opt == '-u': data['user'] = arg elif opt == '-p': data['password'] = arg elif opt == '-s': optional['is_screenshot'] = 'yes' elif opt == '-f': optional['is_final'] = 'yes' elif opt == '-d': data['description'] = arg elif opt == '-c': data['content_file'] = Upload(arg) elif opt == '-e': url = '/e/%s/oup/' % arg elif opt == '-h': host = arg elif opt == '-P': port = int(arg) if len(data) < 4 or url is None: print 'Required argument missing' usage() sys.exit(1) data.update(optional) http_request(data, host, port, url)