Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

filepost.py 2.3KB

1 year ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. from __future__ import annotations
  2. import binascii
  3. import codecs
  4. import os
  5. import typing
  6. from io import BytesIO
  7. from .fields import _TYPE_FIELD_VALUE_TUPLE, RequestField
  8. writer = codecs.lookup("utf-8")[3]
  9. _TYPE_FIELDS_SEQUENCE = typing.Sequence[
  10. typing.Union[typing.Tuple[str, _TYPE_FIELD_VALUE_TUPLE], RequestField]
  11. ]
  12. _TYPE_FIELDS = typing.Union[
  13. _TYPE_FIELDS_SEQUENCE,
  14. typing.Mapping[str, _TYPE_FIELD_VALUE_TUPLE],
  15. ]
  16. def choose_boundary() -> str:
  17. """
  18. Our embarrassingly-simple replacement for mimetools.choose_boundary.
  19. """
  20. return binascii.hexlify(os.urandom(16)).decode()
  21. def iter_field_objects(fields: _TYPE_FIELDS) -> typing.Iterable[RequestField]:
  22. """
  23. Iterate over fields.
  24. Supports list of (k, v) tuples and dicts, and lists of
  25. :class:`~urllib3.fields.RequestField`.
  26. """
  27. iterable: typing.Iterable[RequestField | tuple[str, _TYPE_FIELD_VALUE_TUPLE]]
  28. if isinstance(fields, typing.Mapping):
  29. iterable = fields.items()
  30. else:
  31. iterable = fields
  32. for field in iterable:
  33. if isinstance(field, RequestField):
  34. yield field
  35. else:
  36. yield RequestField.from_tuples(*field)
  37. def encode_multipart_formdata(
  38. fields: _TYPE_FIELDS, boundary: str | None = None
  39. ) -> tuple[bytes, str]:
  40. """
  41. Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
  42. :param fields:
  43. Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`).
  44. Values are processed by :func:`urllib3.fields.RequestField.from_tuples`.
  45. :param boundary:
  46. If not specified, then a random boundary will be generated using
  47. :func:`urllib3.filepost.choose_boundary`.
  48. """
  49. body = BytesIO()
  50. if boundary is None:
  51. boundary = choose_boundary()
  52. for field in iter_field_objects(fields):
  53. body.write(f"--{boundary}\r\n".encode("latin-1"))
  54. writer(body).write(field.render_headers())
  55. data = field.data
  56. if isinstance(data, int):
  57. data = str(data) # Backwards compatibility
  58. if isinstance(data, str):
  59. writer(body).write(data)
  60. else:
  61. body.write(data)
  62. body.write(b"\r\n")
  63. body.write(f"--{boundary}--\r\n".encode("latin-1"))
  64. content_type = f"multipart/form-data; boundary={boundary}"
  65. return body.getvalue(), content_type