diff --git a/oxlib/__init__.py b/oxlib/__init__.py index 6b12355..7961627 100644 --- a/oxlib/__init__.py +++ b/oxlib/__init__.py @@ -8,8 +8,10 @@ from format import * from html import * from iso import * from text import * +from form import * import cache import net from torrent import * + diff --git a/oxlib/form.py b/oxlib/form.py new file mode 100644 index 0000000..35a97f7 --- /dev/null +++ b/oxlib/form.py @@ -0,0 +1,73 @@ +import itertools +import mimetools +import mimetypes + + +__all__ = ['MultiPartForm'] + +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() + return + + 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)) + return + + def add_file(self, fieldname, filename, fileHandle, mimetype=None): + """Add a file to be uploaded.""" + if hasattr(fileHandle, 'read'): + body = fileHandle.read() + else: + body = fileHandle + if mimetype is None: + mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream' + self.files.append((fieldname, filename, mimetype, body)) + return + + 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) +