Mercurial > rinkhals
annotate pyweek-upload.py @ 498:62b9a4e21f1a
chickens in closed buildings deselected. building opens if you put in chickens and it's not full. opening building with move or select tool allows rearrangement of chickens in building. fixed multiselect in buildings.
author | Adrianna Pińska <adrianna.pinska@gmail.com> |
---|---|
date | Wed, 25 Nov 2009 23:51:33 +0000 |
parents | 615a5afaf1a4 |
children |
rev | line source |
---|---|
2 | 1 ''' |
2 Upload script specifically engineered for the PyWeek challenge. | |
3 | |
4 Handles authentication and gives upload progress feedback. | |
5 ''' | |
6 import sys, os, httplib, cStringIO, socket, time, getopt | |
7 | |
8 class Upload: | |
9 def __init__(self, filename): | |
10 self.filename = filename | |
11 | |
12 boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' | |
13 sep_boundary = '\n--' + boundary | |
14 end_boundary = sep_boundary + '--' | |
15 | |
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. | |
19 ''' | |
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] | |
24 for value in 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() | |
31 else: | |
32 ret.write('\nContent-Disposition: form-data; name="%s"'%key) | |
33 ret.write("\n\n") | |
76
615a5afaf1a4
Make integer data keys (i.e. the API version number) work.
Simon Cross <hodgestar@gmail.com>
parents:
2
diff
changeset
|
34 value = str(value) |
615a5afaf1a4
Make integer data keys (i.e. the API version number) work.
Simon Cross <hodgestar@gmail.com>
parents:
2
diff
changeset
|
35 ret.write(value) |
2 | 36 if value and value[-1] == '\r': |
37 ret.write('\n') # write an extra newline | |
38 ret.write(end_boundary) | |
39 return ret.getvalue() | |
40 | |
41 class Progress: | |
42 def __init__(self, info, data): | |
43 self.info = info | |
44 self.tosend = len(data) | |
45 self.total = self.tosend/1024 | |
46 self.data = cStringIO.StringIO(data) | |
47 self.start = self.now = time.time() | |
48 self.sent = 0 | |
49 self.num = 0 | |
50 self.stepsize = self.total / 100 or 1 | |
51 self.steptimes = [] | |
52 self.display() | |
53 | |
54 def __iter__(self): return self | |
55 | |
56 def next(self): | |
57 self.num += 1 | |
58 if self.sent >= self.tosend: | |
59 print self.info, 'done', ' '*(75-len(self.info)-6) | |
60 sys.stdout.flush() | |
61 raise StopIteration | |
62 | |
63 chunk = self.data.read(1024) | |
64 self.sent += len(chunk) | |
65 #print (self.num, self.stepsize, self.total, self.sent, self.tosend) | |
66 | |
67 if self.num % self.stepsize: | |
68 return chunk | |
69 self.display() | |
70 return chunk | |
71 | |
72 def display(self): | |
73 # figure how long we've spent - guess how long to go | |
74 now = time.time() | |
75 steptime = now - self.now | |
76 self.steptimes.insert(0, steptime) | |
77 if len(self.steptimes) > 5: | |
78 self.steptimes.pop() | |
79 steptime = sum(self.steptimes) / len(self.steptimes) | |
80 self.now = now | |
81 eta = steptime * ((self.total - self.num)/self.stepsize) | |
82 | |
83 # tell it like it is (or might be) | |
84 if now - self.start > 3: | |
85 M = eta / 60 | |
86 H = M / 60 | |
87 M = M % 60 | |
88 S = eta % 60 | |
89 if self.total: | |
90 s = '%s %2d%% (ETA %02d:%02d:%02d)'%(self.info, | |
91 self.num * 100. / self.total, H, M, S) | |
92 else: | |
93 s = '%s 0%% (ETA %02d:%02d:%02d)'%(self.info, H, M, S) | |
94 elif self.total: | |
95 s = '%s %2d%%'%(self.info, self.num * 100. / self.total) | |
96 else: | |
97 s = '%s %d done'%(self.info, self.num) | |
98 sys.stdout.write(s + ' '*(75-len(s)) + '\r') | |
99 sys.stdout.flush() | |
100 | |
101 class progressHTTPConnection(httplib.HTTPConnection): | |
102 def progress_send(self, str): | |
103 """Send `str' to the server.""" | |
104 if self.sock is None: | |
105 self.connect() | |
106 | |
107 p = Progress('Uploading', str) | |
108 for chunk in p: | |
109 sent = 0 | |
110 while sent != len(chunk): | |
111 try: | |
112 sent += self.sock.send(chunk) | |
113 except socket.error, v: | |
114 if v[0] == 32: # Broken pipe | |
115 self.close() | |
116 raise | |
117 p.display() | |
118 | |
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 | |
124 | |
125 def http_request(data, server, port, url): | |
126 h = progressHTTP(server, port) | |
127 | |
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) | |
133 h.endheaders() | |
134 | |
135 h.progress_send(data) | |
136 | |
137 errcode, errmsg, headers = h.getreply() | |
138 | |
139 f = h.getfile() | |
140 response = f.read().strip() | |
141 f.close() | |
142 | |
143 print '%s %s'%(errcode, errmsg) | |
144 if response: print response | |
145 | |
146 def usage(): | |
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. | |
149 | |
150 REQUIRED ARGUMENTS: | |
151 -u username | |
152 -p password | |
153 -d description of file | |
154 -c file to upload | |
155 -e entry short name | |
156 | |
157 OPTIONAL ARGUMENTS: | |
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) | |
162 | |
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. | |
165 ''' | |
166 | |
167 | |
168 if __name__ == '__main__': | |
169 try: | |
170 optlist, args = getopt.getopt(sys.argv[1:], 'e:u:p:sfd:h:P:c:') | |
171 except getopt.GetoptError, message: | |
172 print message | |
173 usage() | |
174 sys.exit(1) | |
175 host = 'www.pyweek.org' | |
176 port = 80 | |
177 data = dict(version=2) | |
178 optional = {} | |
179 url = None | |
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) | |
190 | |
191 if len(data) < 4 or url is None: | |
192 print 'Required argument missing' | |
193 usage() | |
194 sys.exit(1) | |
195 | |
196 data.update(optional) | |
197 http_request(data, host, port, url) | |
198 |