Helper class for multipart/form-data and application/x-www-form-urlencoded body generation.
| 49 | |
| 50 | |
| 51 | class FormData: |
| 52 | """Helper class for multipart/form-data and |
| 53 | application/x-www-form-urlencoded body generation.""" |
| 54 | |
| 55 | def __init__(self, fields=()): |
| 56 | from . import multipart |
| 57 | self._writer = multipart.MultipartWriter('form-data') |
| 58 | self._fields = [] |
| 59 | self._is_multipart = False |
| 60 | |
| 61 | if isinstance(fields, dict): |
| 62 | fields = list(fields.items()) |
| 63 | elif not isinstance(fields, (list, tuple)): |
| 64 | fields = (fields,) |
| 65 | self.add_fields(*fields) |
| 66 | |
| 67 | @property |
| 68 | def is_multipart(self): |
| 69 | return self._is_multipart |
| 70 | |
| 71 | @property |
| 72 | def content_type(self): |
| 73 | if self._is_multipart: |
| 74 | return self._writer.headers[hdrs.CONTENT_TYPE] |
| 75 | else: |
| 76 | return 'application/x-www-form-urlencoded' |
| 77 | |
| 78 | def add_field(self, name, value, *, content_type=None, filename=None, |
| 79 | content_transfer_encoding=None): |
| 80 | |
| 81 | if isinstance(value, io.IOBase): |
| 82 | self._is_multipart = True |
| 83 | elif isinstance(value, (bytes, bytearray, memoryview)): |
| 84 | if filename is None and content_transfer_encoding is None: |
| 85 | filename = name |
| 86 | |
| 87 | type_options = multidict.MultiDict({'name': name}) |
| 88 | if filename is not None and not isinstance(filename, str): |
| 89 | raise TypeError('filename must be an instance of str. ' |
| 90 | 'Got: %s' % filename) |
| 91 | if filename is None and isinstance(value, io.IOBase): |
| 92 | filename = guess_filename(value, name) |
| 93 | if filename is not None: |
| 94 | type_options['filename'] = filename |
| 95 | self._is_multipart = True |
| 96 | |
| 97 | headers = {} |
| 98 | if content_type is not None: |
| 99 | if not isinstance(content_type, str): |
| 100 | raise TypeError('content_type must be an instance of str. ' |
| 101 | 'Got: %s' % content_type) |
| 102 | headers[hdrs.CONTENT_TYPE] = content_type |
| 103 | self._is_multipart = True |
| 104 | if content_transfer_encoding is not None: |
| 105 | if not isinstance(content_transfer_encoding, str): |
| 106 | raise TypeError('content_transfer_encoding must be an instance' |
| 107 | ' of str. Got: %s' % content_transfer_encoding) |
| 108 | headers[hdrs.CONTENT_TRANSFER_ENCODING] = content_transfer_encoding |