2 Upload script specifically engineered for the PyWeek challenge.
4 Handles authentication and gives upload progress feedback.
6 import sys, os, httplib, cStringIO, socket, time, getopt
9 def __init__(self, filename):
10 self.filename = filename
12 boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
13 sep_boundary = '\n--' + boundary
14 end_boundary = sep_boundary + '--'
16 def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary):
17 '''Take the mapping of data and construct the body of a
18 multipart/form-data message with it using the indicated boundaries.
20 ret = cStringIO.StringIO()
21 for key, value in data.items():
22 # handle multiple entries for the same name
23 if type(value) != type([]): value = [value]
25 ret.write(sep_boundary)
26 if isinstance(value, Upload):
27 ret.write('\nContent-Disposition: form-data; name="%s"'%key)
28 filename = os.path.basename(value.filename)
29 ret.write('; filename="%s"\n\n'%filename)
30 value = open(os.path.join(value.filename), "rb").read()
32 ret.write('\nContent-Disposition: form-data; name="%s"'%key)
36 if value and value[-1] == '\r':
37 ret.write('\n') # write an extra newline
38 ret.write(end_boundary)
42 def __init__(self, info, data):
44 self.tosend = len(data)
45 self.total = self.tosend/1024
46 self.data = cStringIO.StringIO(data)
47 self.start = self.now = time.time()
50 self.stepsize = self.total / 100 or 1
54 def __iter__(self): return self
58 if self.sent >= self.tosend:
59 print self.info, 'done', ' '*(75-len(self.info)-6)
63 chunk = self.data.read(1024)
64 self.sent += len(chunk)
65 #print (self.num, self.stepsize, self.total, self.sent, self.tosend)
67 if self.num % self.stepsize:
73 # figure how long we've spent - guess how long to go
75 steptime = now - self.now
76 self.steptimes.insert(0, steptime)
77 if len(self.steptimes) > 5:
79 steptime = sum(self.steptimes) / len(self.steptimes)
81 eta = steptime * ((self.total - self.num)/self.stepsize)
83 # tell it like it is (or might be)
84 if now - self.start > 3:
90 s = '%s %2d%% (ETA %02d:%02d:%02d)'%(self.info,
91 self.num * 100. / self.total, H, M, S)
93 s = '%s 0%% (ETA %02d:%02d:%02d)'%(self.info, H, M, S)
95 s = '%s %2d%%'%(self.info, self.num * 100. / self.total)
97 s = '%s %d done'%(self.info, self.num)
98 sys.stdout.write(s + ' '*(75-len(s)) + '\r')
101 class progressHTTPConnection(httplib.HTTPConnection):
102 def progress_send(self, str):
103 """Send `str' to the server."""
104 if self.sock is None:
107 p = Progress('Uploading', str)
110 while sent != len(chunk):
112 sent += self.sock.send(chunk)
113 except socket.error, v:
114 if v[0] == 32: # Broken pipe
119 class progressHTTP(httplib.HTTP):
120 _connection_class = progressHTTPConnection
121 def _setup(self, conn):
122 httplib.HTTP._setup(self, conn)
123 self.progress_send = self._conn.progress_send
125 def http_request(data, server, port, url):
126 h = progressHTTP(server, port)
128 data = mimeEncode(data)
129 h.putrequest('POST', url)
130 h.putheader('Content-type', 'multipart/form-data; boundary=%s'%boundary)
131 h.putheader('Content-length', str(len(data)))
132 h.putheader('Host', server)
135 h.progress_send(data)
137 errcode, errmsg, headers = h.getreply()
140 response = f.read().strip()
143 print '%s %s'%(errcode, errmsg)
144 if response: print response
147 print '''This program is to be used to upload files to the PyWeek system.
148 You may use it to upload screenshots or code submissions.
153 -d description of file
158 -s file is a screenshot
159 -f file is FINAL submission
160 -h override default host name (www.pyweek.org)
161 -P override default host port (80)
163 In order to qualify for judging at the end of the challenge, you MUST
164 upload your source and check the "Final Submission" checkbox.
168 if __name__ == '__main__':
170 optlist, args = getopt.getopt(sys.argv[1:], 'e:u:p:sfd:h:P:c:')
171 except getopt.GetoptError, message:
175 host = 'www.pyweek.org'
177 data = dict(version=2)
180 for opt, arg in optlist:
181 if opt == '-u': data['user'] = arg
182 elif opt == '-p': data['password'] = arg
183 elif opt == '-s': optional['is_screenshot'] = 'yes'
184 elif opt == '-f': optional['is_final'] = 'yes'
185 elif opt == '-d': data['description'] = arg
186 elif opt == '-c': data['content_file'] = Upload(arg)
187 elif opt == '-e': url = '/e/%s/oup/'%arg
188 elif opt == '-h': host = arg
189 elif opt == '-P': port = int(arg)
191 if len(data) < 4 or url is None:
192 print 'Required argument missing'
196 data.update(optional)
197 http_request(data, host, port, url)