Mercurial > hg > simpypi
comparison tests/multipart.py @ 63:af1476a936fc
add a multipart processor so we can post damn files
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Thu, 01 Mar 2012 16:57:00 -0800 |
parents | |
children | bb8d993376aa |
comparison
equal
deleted
inserted
replaced
62:7c154953acc4 | 63:af1476a936fc |
---|---|
1 """ | |
2 from | |
3 http://www.doughellmann.com/PyMOTW/urllib2/#uploading-files | |
4 | |
5 Very very sad that python2 stdlib doesn't have this | |
6 """ | |
7 | |
8 import itertools | |
9 import mimetools | |
10 import mimetypes | |
11 from cStringIO import StringIO | |
12 import urllib | |
13 import urllib2 | |
14 | |
15 class MultiPartForm(object): | |
16 """Accumulate the data to be used when posting a form.""" | |
17 | |
18 def __init__(self): | |
19 self.form_fields = [] | |
20 self.files = [] | |
21 self.boundary = mimetools.choose_boundary() | |
22 | |
23 def get_content_type(self): | |
24 return 'multipart/form-data; boundary=%s' % self.boundary | |
25 | |
26 def add_field(self, name, value): | |
27 """Add a simple field to the form data.""" | |
28 self.form_fields.append((name, value)) | |
29 | |
30 def add_file(self, fieldname, filename, fileHandle, mimetype=None): | |
31 """Add a file to be uploaded.""" | |
32 body = fileHandle.read() | |
33 if mimetype is None: | |
34 mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' | |
35 self.files.append((fieldname, filename, mimetype, body)) | |
36 | |
37 def post(self, url): | |
38 request = urllib2.Request(url) | |
39 body = str(self) | |
40 request.add_header('Content-type', self.get_content_type()) | |
41 request.add_header('Content-length', len(body)) | |
42 request.add_data(body) | |
43 return urllib2.urlopen(request) | |
44 | |
45 def __str__(self): | |
46 """Return a string representing the form data, including attached files.""" | |
47 # Build a list of lists, each containing "lines" of the | |
48 # request. Each part is separated by a boundary string. | |
49 # Once the list is built, return a string where each | |
50 # line is separated by '\r\n'. | |
51 parts = [] | |
52 part_boundary = '--' + self.boundary | |
53 | |
54 # Add the form fields | |
55 parts.extend( | |
56 [ part_boundary, | |
57 'Content-Disposition: form-data; name="%s"' % name, | |
58 '', | |
59 value, | |
60 ] | |
61 for name, value in self.form_fields | |
62 ) | |
63 | |
64 # Add the files to upload | |
65 parts.extend( | |
66 [ part_boundary, | |
67 'Content-Disposition: file; name="%s"; filename="%s"' % \ | |
68 (field_name, filename), | |
69 'Content-Type: %s' % content_type, | |
70 '', | |
71 body, | |
72 ] | |
73 for field_name, filename, content_type, body in self.files | |
74 ) | |
75 | |
76 # Flatten the list and add closing boundary marker, | |
77 # then return CR+LF separated data | |
78 flattened = list(itertools.chain(*parts)) | |
79 flattened.append('--' + self.boundary + '--') | |
80 flattened.append('') | |
81 return '\r\n'.join(flattened) |