microdot.multipart — análise de multipart/form-data

Analisa corpos de pedido Content-Type: multipart/form-data — a codificação utilizada pelos navegadores em formulários que incluem campos <input type="file">. Dois tipos de API:

  • Um FormDataIter de streaming que produz campos um de cada vez — útil quando a aplicação tem de processar uploads muito grandes peça a peça num dispositivo com memória limitada.

  • Um decorador with_form_data() que coloca tudo em buffer e preenche request.form / request.files — a API conveniente para uploads de tamanho normal.

class FormDataIter

class microdot.multipart.FormDataIter(request)

Iterador assíncrono sobre as partes do corpo multipart de request. Os valores produzidos são tuplos (name, value); value é uma str para campos normais e um FileUpload para campos de ficheiro.

Utilizado diretamente quando a memória é mais importante do que a ergonomia:

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'

Nota

Ao iterar sobre campos de ficheiro, o ficheiro deve ser consumido (via FileUpload.read() ou FileUpload.save()) antes da próxima iteração async for — o stream subjacente é invalidado quando a iteração avança.

buffer_size: int

Atributo de classe. Tamanho do chunk utilizado na leitura do stream do pedido. Predefinição: 256 bytes. Aumente para maior débito à custa de RAM.

class FileUpload

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

Um único ficheiro enviado. As instâncias são produzidas por FormDataIter e recolhidas em request.files por with_form_data(). As aplicações normalmente não constroem FileUpload diretamente.

filename: str

O nome original do ficheiro tal como o cliente o enviou (não é de confiança — não passe a open() sem sanitização).

content_type: str | None

O tipo MIME do cabeçalho Content-Type da parte, ou None se não for fornecido.

max_memory_size: int

Atributo de classe. Limiar (em bytes) acima do qual copy() muda de buffer em memória para um ficheiro temporário. Predefinição: 1024.

async read(n: int = -1)

Lê até n bytes do stream de upload. -1 lê até ao fim.

async save(path_or_file)

Guarda o upload em path_or_file, que pode ser um caminho no sistema de ficheiros ou um objeto de ficheiro já aberto.

async copy(max_memory_size: int | None = None)

Coloca o upload em buffer (em RAM ou num ficheiro temporário, consoante max_memory_size) para que o restante do corpo multipart possa ser analisado sem que o stream original seja invalidado. O decorador with_form_data() chama isto automaticamente.

async close()

Liberta qualquer ficheiro temporário criado por copy(). Chamado automaticamente quando o pedido termina, se o upload chegou a request.files via with_form_data().

Decoradores ao nível do módulo

microdot.multipart.with_form_data(f)

Decorador que analisa o corpo multipart antecipadamente e preenche request.form e request.files antes de o handler ser executado:

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'

Os uploads de ficheiros são colocados em buffer via FileUpload.copy(), pelo que o handler pode iterar livremente sobre request.files e request.form. Os ficheiros temporários são limpos automaticamente quando o pedido termina.

Para uploads maiores do que alguns megabytes, prefira a API de streaming FormDataIter; with_form_data() acumula o pedido inteiro em memória ou no sistema de ficheiros antes de o handler ser executado.