Mercurial > nagslang
view pyweek_upload.py @ 55:26d7bb8c09c8
Only save levels if the loops are closed
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Sun, 01 Sep 2013 18:50:19 +0200 |
parents | e30d192e9031 |
children |
line wrap: on
line source
''' Upload script specifically engineered for the PyWeek challenge. Handles authentication and gives upload progress feedback. ''' import sys import os import httplib import cStringIO import socket import time import getopt class Upload(object): 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 not isinstance(value, list): 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(object): 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)