microdot.multipart — разбор multipart/form-data

Разбирает тела запросов с Content-Type: multipart/form-data – кодировку, которую браузеры используют для форм, включающих поля <input type="file">. Два варианта API:

  • Потоковый FormDataIter, выдающий поля по одному – полезно, когда приложению приходится обрабатывать очень большие загрузки по частям на устройстве с ограниченной памятью.

  • Декоратор with_form_data(), который буферизует всё и заполняет request.form / request.files – удобный API для загрузок обычного размера.

class FormDataIter

class microdot.multipart.FormDataIter(request)

Асинхронный итератор по частям multipart-тела request. Выдаваемые значения представляют собой кортежи (name, value); value является str для обычных полей и FileUpload для полей файлов.

Используется напрямую, когда память важнее эргономики:

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'

Примечание

При итерации по полям файлов файл должен быть прочитан (через FileUpload.read() или FileUpload.save()) до следующей итерации async for – лежащий в основе поток становится недействительным при продвижении итерации.

buffer_size: int

Атрибут класса. Размер блока, используемый при чтении из потока запроса. По умолчанию 256 байт. Увеличьте для большей пропускной способности ценой расхода ОЗУ.

class FileUpload

class microdot.multipart.FileUpload(filename: str, content_type: str | None, read)

Один загруженный файл. Экземпляры выдаются FormDataIter и собираются в request.files декоратором with_form_data(). Приложения обычно не создают FileUpload напрямую.

filename: str

Исходное имя файла в том виде, в каком его прислал клиент (недоверенное – не передавайте в open() без санитизации).

content_type: str | None

MIME-тип из заголовка Content-Type части или None, если не предоставлен.

max_memory_size: int

Атрибут класса. Порог (в байтах), выше которого copy() переключается с буферизации в памяти на временный файл. По умолчанию 1024.

async read(n: int = -1)

Читает до n байт из потока загрузки. -1 читает до конца.

async save(path_or_file)

Сохраняет загрузку в path_or_file, который может быть путём в файловой системе или уже открытым объектом файла.

async copy(max_memory_size: int | None = None)

Буферизует загрузку (в ОЗУ или во временном файле, в зависимости от max_memory_size), чтобы остальную часть multipart-тела можно было разобрать без того, чтобы исходный поток стал недействительным. Декоратор with_form_data() вызывает это автоматически.

async close()

Освобождает любой временный файл, созданный copy(). Вызывается автоматически по завершении запроса, если загрузка достигла request.files через with_form_data().

Декораторы уровня модуля

microdot.multipart.with_form_data(f)

Декоратор, который заранее разбирает multipart-тело и заполняет request.form и request.files до выполнения обработчика:

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'

Загрузки файлов буферизуются через FileUpload.copy(), поэтому обработчик может свободно итерировать request.files и request.form. Временные файлы очищаются автоматически по завершении запроса.

Для загрузок размером более пары мегабайт предпочтительнее потоковый API FormDataIter; with_form_data() накапливает весь запрос в памяти или в файловой системе перед выполнением обработчика.