# HG changeset patch # User Jeff Hammel # Date 1330649820 28800 # Node ID af1476a936fc7efceff7fd2bcd2a4ae3ed6a1e28 # Parent 7c154953acc4604b5ee593c6cc14cb99279b4718 add a multipart processor so we can post damn files diff -r 7c154953acc4 -r af1476a936fc tests/multipart.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/multipart.py Thu Mar 01 16:57:00 2012 -0800 @@ -0,0 +1,81 @@ +""" +from +http://www.doughellmann.com/PyMOTW/urllib2/#uploading-files + +Very very sad that python2 stdlib doesn't have this +""" + +import itertools +import mimetools +import mimetypes +from cStringIO import StringIO +import urllib +import urllib2 + +class MultiPartForm(object): + """Accumulate the data to be used when posting a form.""" + + def __init__(self): + self.form_fields = [] + self.files = [] + self.boundary = mimetools.choose_boundary() + + def get_content_type(self): + return 'multipart/form-data; boundary=%s' % self.boundary + + def add_field(self, name, value): + """Add a simple field to the form data.""" + self.form_fields.append((name, value)) + + def add_file(self, fieldname, filename, fileHandle, mimetype=None): + """Add a file to be uploaded.""" + body = fileHandle.read() + if mimetype is None: + mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' + self.files.append((fieldname, filename, mimetype, body)) + + def post(self, url): + request = urllib2.Request(url) + body = str(self) + request.add_header('Content-type', self.get_content_type()) + request.add_header('Content-length', len(body)) + request.add_data(body) + return urllib2.urlopen(request) + + def __str__(self): + """Return a string representing the form data, including attached files.""" + # Build a list of lists, each containing "lines" of the + # request. Each part is separated by a boundary string. + # Once the list is built, return a string where each + # line is separated by '\r\n'. + parts = [] + part_boundary = '--' + self.boundary + + # Add the form fields + parts.extend( + [ part_boundary, + 'Content-Disposition: form-data; name="%s"' % name, + '', + value, + ] + for name, value in self.form_fields + ) + + # Add the files to upload + parts.extend( + [ part_boundary, + 'Content-Disposition: file; name="%s"; filename="%s"' % \ + (field_name, filename), + 'Content-Type: %s' % content_type, + '', + body, + ] + for field_name, filename, content_type, body in self.files + ) + + # Flatten the list and add closing boundary marker, + # then return CR+LF separated data + flattened = list(itertools.chain(*parts)) + flattened.append('--' + self.boundary + '--') + flattened.append('') + return '\r\n'.join(flattened) diff -r 7c154953acc4 -r af1476a936fc tests/test.py --- a/tests/test.py Thu Mar 01 16:20:44 2012 -0800 +++ b/tests/test.py Thu Mar 01 16:57:00 2012 -0800 @@ -41,8 +41,8 @@ doctest_args['optionflags'] = doctest.REPORT_ONLY_FIRST_FAILURE # gather tests - tests = [ test for test in os.listdir(directory) - if test.endswith('.txt') ] + tests = [test for test in os.listdir(directory) + if test.endswith('.txt')] # run the tests for test in tests: