comparison pyweek-upload.py @ 1:c90a6586cd66

PEP8-ify skellington (because)
author Neil Muller <drnlmuller@gmail.com>
date Sun, 06 May 2012 10:32:24 +0200
parents d0de8832774b
children
comparison
equal deleted inserted replaced
0:d0de8832774b 1:c90a6586cd66
1 ''' 1 '''
2 Upload script specifically engineered for the PyWeek challenge. 2 Upload script specifically engineered for the PyWeek challenge.
3 3
4 Handles authentication and gives upload progress feedback. 4 Handles authentication and gives upload progress feedback.
5 ''' 5 '''
6 import sys, os, httplib, cStringIO, socket, time, getopt 6 import sys
7 import os
8 import httplib
9 import cStringIO
10 import socket
11 import time
12 import getopt
13
7 14
8 class Upload: 15 class Upload:
9 def __init__(self, filename): 16 def __init__(self, filename):
10 self.filename = filename 17 self.filename = filename
11 18
12 boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' 19 boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
13 sep_boundary = '\n--' + boundary 20 sep_boundary = '\n--' + boundary
14 end_boundary = sep_boundary + '--' 21 end_boundary = sep_boundary + '--'
22
15 23
16 def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary): 24 def mimeEncode(data, sep_boundary=sep_boundary, end_boundary=end_boundary):
17 '''Take the mapping of data and construct the body of a 25 '''Take the mapping of data and construct the body of a
18 multipart/form-data message with it using the indicated boundaries. 26 multipart/form-data message with it using the indicated boundaries.
19 ''' 27 '''
20 ret = cStringIO.StringIO() 28 ret = cStringIO.StringIO()
21 for key, value in data.items(): 29 for key, value in data.items():
22 # handle multiple entries for the same name 30 # handle multiple entries for the same name
23 if type(value) != type([]): value = [value] 31 if type(value) != type([]):
32 value = [value]
24 for value in value: 33 for value in value:
25 ret.write(sep_boundary) 34 ret.write(sep_boundary)
26 if isinstance(value, Upload): 35 if isinstance(value, Upload):
27 ret.write('\nContent-Disposition: form-data; name="%s"'%key) 36 ret.write('\nContent-Disposition: form-data; name="%s"' % key)
28 filename = os.path.basename(value.filename) 37 filename = os.path.basename(value.filename)
29 ret.write('; filename="%s"\n\n'%filename) 38 ret.write('; filename="%s"\n\n' % filename)
30 value = open(os.path.join(value.filename), "rb").read() 39 value = open(os.path.join(value.filename), "rb").read()
31 else: 40 else:
32 ret.write('\nContent-Disposition: form-data; name="%s"'%key) 41 ret.write('\nContent-Disposition: form-data; name="%s"' % key)
33 ret.write("\n\n") 42 ret.write("\n\n")
34 value = str(value) 43 value = str(value)
35 ret.write(str(value)) 44 ret.write(str(value))
36 if value and value[-1] == '\r': 45 if value and value[-1] == '\r':
37 ret.write('\n') # write an extra newline 46 ret.write('\n') # write an extra newline
38 ret.write(end_boundary) 47 ret.write(end_boundary)
39 return ret.getvalue() 48 return ret.getvalue()
40 49
50
41 class Progress: 51 class Progress:
42 def __init__(self, info, data): 52 def __init__(self, info, data):
43 self.info = info 53 self.info = info
44 self.tosend = len(data) 54 self.tosend = len(data)
45 self.total = self.tosend/1024 55 self.total = self.tosend / 1024
46 self.data = cStringIO.StringIO(data) 56 self.data = cStringIO.StringIO(data)
47 self.start = self.now = time.time() 57 self.start = self.now = time.time()
48 self.sent = 0 58 self.sent = 0
49 self.num = 0 59 self.num = 0
50 self.stepsize = self.total / 100 or 1 60 self.stepsize = self.total / 100 or 1
51 self.steptimes = [] 61 self.steptimes = []
52 self.display() 62 self.display()
53 63
54 def __iter__(self): return self 64 def __iter__(self):
65 return self
55 66
56 def next(self): 67 def next(self):
57 self.num += 1 68 self.num += 1
58 if self.sent >= self.tosend: 69 if self.sent >= self.tosend:
59 print self.info, 'done', ' '*(75-len(self.info)-6) 70 print self.info, 'done', ' ' * (75 - len(self.info) - 6)
60 sys.stdout.flush() 71 sys.stdout.flush()
61 raise StopIteration 72 raise StopIteration
62 73
63 chunk = self.data.read(1024) 74 chunk = self.data.read(1024)
64 self.sent += len(chunk) 75 self.sent += len(chunk)
76 self.steptimes.insert(0, steptime) 87 self.steptimes.insert(0, steptime)
77 if len(self.steptimes) > 5: 88 if len(self.steptimes) > 5:
78 self.steptimes.pop() 89 self.steptimes.pop()
79 steptime = sum(self.steptimes) / len(self.steptimes) 90 steptime = sum(self.steptimes) / len(self.steptimes)
80 self.now = now 91 self.now = now
81 eta = steptime * ((self.total - self.num)/self.stepsize) 92 eta = steptime * ((self.total - self.num) / self.stepsize)
82 93
83 # tell it like it is (or might be) 94 # tell it like it is (or might be)
84 if now - self.start > 3: 95 if now - self.start > 3:
85 M = eta / 60 96 M = eta / 60
86 H = M / 60 97 H = M / 60
87 M = M % 60 98 M = M % 60
88 S = eta % 60 99 S = eta % 60
89 if self.total: 100 if self.total:
90 s = '%s %2d%% (ETA %02d:%02d:%02d)'%(self.info, 101 s = '%s %2d%% (ETA %02d:%02d:%02d)' % (self.info,
91 self.num * 100. / self.total, H, M, S) 102 self.num * 100. / self.total, H, M, S)
92 else: 103 else:
93 s = '%s 0%% (ETA %02d:%02d:%02d)'%(self.info, H, M, S) 104 s = '%s 0%% (ETA %02d:%02d:%02d)' % (self.info, H, M, S)
94 elif self.total: 105 elif self.total:
95 s = '%s %2d%%'%(self.info, self.num * 100. / self.total) 106 s = '%s %2d%%' % (self.info, self.num * 100. / self.total)
96 else: 107 else:
97 s = '%s %d done'%(self.info, self.num) 108 s = '%s %d done' % (self.info, self.num)
98 sys.stdout.write(s + ' '*(75-len(s)) + '\r') 109 sys.stdout.write(s + ' ' * (75 - len(s)) + '\r')
99 sys.stdout.flush() 110 sys.stdout.flush()
111
100 112
101 class progressHTTPConnection(httplib.HTTPConnection): 113 class progressHTTPConnection(httplib.HTTPConnection):
102 def progress_send(self, str): 114 def progress_send(self, str):
103 """Send `str' to the server.""" 115 """Send `str' to the server."""
104 if self.sock is None: 116 if self.sock is None:
114 if v[0] == 32: # Broken pipe 126 if v[0] == 32: # Broken pipe
115 self.close() 127 self.close()
116 raise 128 raise
117 p.display() 129 p.display()
118 130
131
119 class progressHTTP(httplib.HTTP): 132 class progressHTTP(httplib.HTTP):
133
120 _connection_class = progressHTTPConnection 134 _connection_class = progressHTTPConnection
135
121 def _setup(self, conn): 136 def _setup(self, conn):
122 httplib.HTTP._setup(self, conn) 137 httplib.HTTP._setup(self, conn)
123 self.progress_send = self._conn.progress_send 138 self.progress_send = self._conn.progress_send
124 139
140
125 def http_request(data, server, port, url): 141 def http_request(data, server, port, url):
126 h = progressHTTP(server, port) 142 h = progressHTTP(server, port)
127 143
128 data = mimeEncode(data) 144 data = mimeEncode(data)
129 h.putrequest('POST', url) 145 h.putrequest('POST', url)
130 h.putheader('Content-type', 'multipart/form-data; boundary=%s'%boundary) 146 h.putheader('Content-type', 'multipart/form-data; boundary=%s' % boundary)
131 h.putheader('Content-length', str(len(data))) 147 h.putheader('Content-length', str(len(data)))
132 h.putheader('Host', server) 148 h.putheader('Host', server)
133 h.endheaders() 149 h.endheaders()
134 150
135 h.progress_send(data) 151 h.progress_send(data)
138 154
139 f = h.getfile() 155 f = h.getfile()
140 response = f.read().strip() 156 response = f.read().strip()
141 f.close() 157 f.close()
142 158
143 print '%s %s'%(errcode, errmsg) 159 print '%s %s' % (errcode, errmsg)
144 if response: print response 160 if response:
161 print response
162
145 163
146 def usage(): 164 def usage():
147 print '''This program is to be used to upload files to the PyWeek system. 165 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. 166 You may use it to upload screenshots or code submissions.
149 167
176 port = 80 194 port = 80
177 data = dict(version=2) 195 data = dict(version=2)
178 optional = {} 196 optional = {}
179 url = None 197 url = None
180 for opt, arg in optlist: 198 for opt, arg in optlist:
181 if opt == '-u': data['user'] = arg 199 if opt == '-u':
182 elif opt == '-p': data['password'] = arg 200 data['user'] = arg
183 elif opt == '-s': optional['is_screenshot'] = 'yes' 201 elif opt == '-p':
184 elif opt == '-f': optional['is_final'] = 'yes' 202 data['password'] = arg
185 elif opt == '-d': data['description'] = arg 203 elif opt == '-s':
186 elif opt == '-c': data['content_file'] = Upload(arg) 204 optional['is_screenshot'] = 'yes'
187 elif opt == '-e': url = '/e/%s/oup/'%arg 205 elif opt == '-f':
188 elif opt == '-h': host = arg 206 optional['is_final'] = 'yes'
189 elif opt == '-P': port = int(arg) 207 elif opt == '-d':
208 data['description'] = arg
209 elif opt == '-c':
210 data['content_file'] = Upload(arg)
211 elif opt == '-e':
212 url = '/e/%s/oup/' % arg
213 elif opt == '-h':
214 host = arg
215 elif opt == '-P':
216 port = int(arg)
190 217
191 if len(data) < 4 or url is None: 218 if len(data) < 4 or url is None:
192 print 'Required argument missing' 219 print 'Required argument missing'
193 usage() 220 usage()
194 sys.exit(1) 221 sys.exit(1)
195 222
196 data.update(optional) 223 data.update(optional)
197 http_request(data, host, port, url) 224 http_request(data, host, port, url)
198