Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/urllib3/filepost.py: 35%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import annotations
3import binascii
4import codecs
5import os
6import typing
7from io import BytesIO
9from .fields import _TYPE_FIELD_VALUE_TUPLE, RequestField
11writer = codecs.lookup("utf-8")[3]
13_TYPE_FIELDS_SEQUENCE = typing.Sequence[
14 typing.Union[typing.Tuple[str, _TYPE_FIELD_VALUE_TUPLE], RequestField]
15]
16_TYPE_FIELDS = typing.Union[
17 _TYPE_FIELDS_SEQUENCE,
18 typing.Mapping[str, _TYPE_FIELD_VALUE_TUPLE],
19]
22def choose_boundary() -> str:
23 """
24 Our embarrassingly-simple replacement for mimetools.choose_boundary.
25 """
26 return binascii.hexlify(os.urandom(16)).decode()
29def iter_field_objects(fields: _TYPE_FIELDS) -> typing.Iterable[RequestField]:
30 """
31 Iterate over fields.
33 Supports list of (k, v) tuples and dicts, and lists of
34 :class:`~urllib3.fields.RequestField`.
36 """
37 iterable: typing.Iterable[RequestField | tuple[str, _TYPE_FIELD_VALUE_TUPLE]]
39 if isinstance(fields, typing.Mapping):
40 iterable = fields.items()
41 else:
42 iterable = fields
44 for field in iterable:
45 if isinstance(field, RequestField):
46 yield field
47 else:
48 yield RequestField.from_tuples(*field)
51def encode_multipart_formdata(
52 fields: _TYPE_FIELDS, boundary: str | None = None
53) -> tuple[bytes, str]:
54 """
55 Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
57 :param fields:
58 Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`).
59 Values are processed by :func:`urllib3.fields.RequestField.from_tuples`.
61 :param boundary:
62 If not specified, then a random boundary will be generated using
63 :func:`urllib3.filepost.choose_boundary`.
64 """
65 body = BytesIO()
66 if boundary is None:
67 boundary = choose_boundary()
69 for field in iter_field_objects(fields):
70 body.write(f"--{boundary}\r\n".encode("latin-1"))
72 writer(body).write(field.render_headers())
73 data = field.data
75 if isinstance(data, int):
76 data = str(data) # Backwards compatibility
78 if isinstance(data, str):
79 writer(body).write(data)
80 else:
81 body.write(data)
83 body.write(b"\r\n")
85 body.write(f"--{boundary}--\r\n".encode("latin-1"))
87 content_type = f"multipart/form-data; boundary={boundary}"
89 return body.getvalue(), content_type