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) |
