microdot.multipart — multipart/form-data parsing¶
Parses Content-Type: multipart/form-data request bodies – the
encoding browsers use for forms that include <input type="file">
fields. Two flavors of API:
A streaming
FormDataIterthat yields fields one at a time – useful when the application has to handle very large uploads piece by piece on a memory-constrained device.A
with_form_data()decorator that buffers everything and populatesrequest.form/request.files– the convenient API for normal-sized uploads.
class FormDataIter¶
- class microdot.multipart.FormDataIter(request)¶
Async iterator over the parts of request’s multipart body. Yielded values are
(name, value)tuples; value is astrfor regular fields and aFileUploadfor file fields.Used directly when memory matters more than ergonomics:
from microdot.multipart import FormDataIter, FileUpload @app.post('/upload') async def upload(request): async for name, value in FormDataIter(request): if isinstance(value, FileUpload): await value.save('/sdcard/' + value.filename) else: print(name, '=', value) return 'ok'
Note
When iterating over file fields, the file must be consumed (via
FileUpload.read()orFileUpload.save()) before the nextasync foriteration – the underlying stream is invalidated when iteration advances.
class FileUpload¶
- class microdot.multipart.FileUpload(filename: str, content_type: str | None, read)¶
A single uploaded file. Instances are yielded by
FormDataIterand collected intorequest.filesbywith_form_data(). Applications do not normally constructFileUploaddirectly.- filename: str¶
The file’s original name as the client sent it (untrusted – do not pass to
open()without sanitizing).
- content_type: str | None¶
The MIME type from the part’s
Content-Typeheader, orNoneif not provided.
- max_memory_size: int¶
Class attribute. Threshold (in bytes) above which
copy()switches from in-memory buffering to a temporary file. Default 1024.
- async save(path_or_file)¶
Save the upload to path_or_file, which can be a filesystem path or an already-open file object.
- async copy(max_memory_size: int | None = None)¶
Buffer the upload (either in RAM or in a temp file, depending on
max_memory_size) so the rest of the multipart body can be parsed without the original stream being invalidated. Thewith_form_data()decorator calls this automatically.
- async close()¶
Release any temporary file created by
copy(). Called automatically when the request finishes if the upload reachedrequest.filesviawith_form_data().
Module-level decorators¶
- microdot.multipart.with_form_data(f)¶
Decorator that parses the multipart body up front and populates
request.formandrequest.filesbefore the handler runs:from microdot import Microdot from microdot.multipart import with_form_data app = Microdot() @app.post('/upload') @with_form_data async def upload(request): print('fields:', dict(request.form)) for name, file in request.files.items(): await file.save('/sdcard/' + sanitize(file.filename)) return 'ok'
File uploads are buffered via
FileUpload.copy(), so the handler can iteraterequest.filesandrequest.formfreely. Temporary files are cleaned up automatically when the request ends.
For uploads larger than a couple of megabytes, prefer the streaming
FormDataIter API; with_form_data() accumulates the
entire request in memory or on the filesystem before the handler
runs.