2 Upload script specifically engineered for the PyWeek challenge.
4 Handles authentication and gives upload progress feedback.
16 def __init__(self, filename):
17 self.filename = filename
19 boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
20 sep_boundary = '\n--' + boundary
21 end_boundary = sep_boundary + '--'
24 def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary):
25 '''Take the mapping of data and construct the body of a
26 multipart/form-data message with it using the indicated boundaries.
28 ret = cStringIO.StringIO()
29 for key, value in data.items():
30 # handle multiple entries for the same name
31 if not isinstance(value, list):
34 ret.write(sep_boundary)
35 if isinstance(value, Upload):
36 ret.write('\nContent-Disposition: form-data; name="%s"' % key)
37 filename = os.path.basename(value.filename)
38 ret.write('; filename="%s"\n\n' % filename)
39 value = open(os.path.join(value.filename), "rb").read()
41 ret.write('\nContent-Disposition: form-data; name="%s"' % key)
45 if value and value[-1] == '\r':
46 ret.write('\n') # write an extra newline
47 ret.write(end_boundary)
51 class Progress(object):
52 def __init__(self, info, data):
54 self.tosend = len(data)
55 self.total = self.tosend / 1024
56 self.data = cStringIO.StringIO(data)
57 self.start = self.now = time.time()
60 self.stepsize = self.total / 100 or 1
69 if self.sent >= self.tosend:
70 print self.info, 'done', ' ' * (75 - len(self.info) - 6)
74 chunk = self.data.read(1024)
75 self.sent += len(chunk)
76 # print (self.num, self.stepsize, self.total, self.sent, self.tosend)
78 if self.num % self.stepsize:
84 # figure how long we've spent - guess how long to go
86 steptime = now - self.now
87 self.steptimes.insert(0, steptime)
88 if len(self.steptimes) > 5:
90 steptime = sum(self.steptimes) / len(self.steptimes)
92 eta = steptime * ((self.total - self.num) / self.stepsize)
94 # tell it like it is (or might be)
95 if now - self.start > 3:
101 s = '%s %2d%% (ETA %02d:%02d:%02d)' % (
102 self.info, self.num * 100. / self.total, H, M, S)
104 s = '%s 0%% (ETA %02d:%02d:%02d)' % (self.info, H, M, S)
106 s = '%s %2d%%' % (self.info, self.num * 100. / self.total)
108 s = '%s %d done' % (self.info, self.num)
109 sys.stdout.write(s + ' ' * (75 - len(s)) + '\r')
113 class progressHTTPConnection(httplib.HTTPConnection):
114 def progress_send(self, str):
115 """Send `str' to the server."""
116 if self.sock is None:
119 p = Progress('Uploading', str)
122 while sent != len(chunk):
124 sent += self.sock.send(chunk)
125 except socket.error, v:
126 if v[0] == 32: # Broken pipe
132 class progressHTTP(httplib.HTTP):
133 _connection_class = progressHTTPConnection
135 def _setup(self, conn):
136 httplib.HTTP._setup(self, conn)
137 self.progress_send = self._conn.progress_send
140 def http_request(data, server, port, url):
141 h = progressHTTP(server, port)
143 data = mimeEncode(data)
144 h.putrequest('POST', url)
145 h.putheader('Content-type', 'multipart/form-data; boundary=%s' % boundary)
146 h.putheader('Content-length', str(len(data)))
147 h.putheader('Host', server)
150 h.progress_send(data)
152 errcode, errmsg, headers = h.getreply()
155 response = f.read().strip()
158 print '%s %s' % (errcode, errmsg)
164 print '''This program is to be used to upload files to the PyWeek system.
165 You may use it to upload screenshots or code submissions.
170 -d description of file
175 -s file is a screenshot
176 -f file is FINAL submission
177 -h override default host name (www.pyweek.org)
178 -P override default host port (80)
180 In order to qualify for judging at the end of the challenge, you MUST
181 upload your source and check the "Final Submission" checkbox.
185 if __name__ == '__main__':
187 optlist, args = getopt.getopt(sys.argv[1:], 'e:u:p:sfd:h:P:c:')
188 except getopt.GetoptError, message:
192 host = 'www.pyweek.org'
194 data = dict(version=2)
197 for opt, arg in optlist:
201 data['password'] = arg
203 optional['is_screenshot'] = 'yes'
205 optional['is_final'] = 'yes'
207 data['description'] = arg
209 data['content_file'] = Upload(arg)
211 url = '/e/%s/oup/' % arg
217 if len(data) < 4 or url is None:
218 print 'Required argument missing'
222 data.update(optional)
223 http_request(data, host, port, url)