Provide a MultipartBuilder that can be used to produce valid multipart/form-data and offers an API that avoids user errors as much as possible. This can be used in tests or HTTP clients. Having both parsers and generators in one library seems to be a good fit.
API Idea
R = TypeVar("R")
_identity = lambda x: x
class MultipartBuilder(Generic[R]):
def __init__(self, boundary: str, write_func: Callable[[Union[bytes,bytearray]], R] = _identity):
" Create a new builder. "
def add_part(self, name: str, filename: Optional[str] = None, content_type: Optional[str] = None) -> R:
"Start a new text field or file upload."
def write(self, chunk: Union[str, bytes, bytearray]) -> R:
"Write a chunk of data to the current field."
def close(self) -> R:
"Write the final delimiter"
The write_func is responsible for writing a single bytearray to the target stream, or return a value that represents the intent to do so. The builder functions return whatever the write function returns. This allows this builder to be used in both blocking and non-blocking environments. If you pass in an async function, then the return value R will be a coroutine you can await.
Not sure if this is a good idea, though. It might be a little bit to clever and having dedicated APIs for AsyncMultipartBuilder and SansIOMultipartBuilder with proper method signatures may be more intuitive.
Provide a MultipartBuilder that can be used to produce valid
multipart/form-data
and offers an API that avoids user errors as much as possible. This can be used in tests or HTTP clients. Having both parsers and generators in one library seems to be a good fit.API Idea
The
write_func
is responsible for writing a singlebytearray
to the target stream, or return a value that represents the intent to do so. The builder functions return whatever the write function returns. This allows this builder to be used in both blocking and non-blocking environments. If you pass in anasync
function, then the return valueR
will be a coroutine you canawait
.Not sure if this is a good idea, though. It might be a little bit to clever and having dedicated APIs for
AsyncMultipartBuilder
andSansIOMultipartBuilder
with proper method signatures may be more intuitive.