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

Analisa corpos de requisição Content-Type: multipart/form-data – a codificação que os navegadores usam para formulários que incluem campos <input type="file">. Dois tipos de API:

  • Um FormDataIter de streaming que produz os campos um de cada vez – útil quando a aplicação precisa lidar com uploads muito grandes parte por parte em um dispositivo com memória limitada.

  • Um decorador with_form_data() que armazena 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 tuplas (name, value); value é uma str para campos comuns e um FileUpload para campos de arquivo.

Usado diretamente quando a memória importa mais 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 arquivo, o arquivo 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 bloco usado ao ler do stream da requisição. Padrão 256 bytes. Aumente para maior throughput ao custo de RAM.

class FileUpload

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

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

filename: str

O nome original do arquivo como o cliente o enviou (não confiável – não passe para open() sem sanitizar).

content_type: str | None

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

max_memory_size: int

Atributo de classe. Limiar (em bytes) acima do qual copy() troca o buffer em memória por um arquivo temporário. Padrão 1024.

async read(n: int = -1)

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

async save(path_or_file)

Salva o upload em path_or_file, que pode ser um caminho do sistema de arquivos ou um objeto de arquivo já aberto.

async copy(max_memory_size: int | None = None)

Armazena o upload em buffer (seja na RAM ou em um arquivo temporário, dependendo de 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 isso automaticamente.

async close()

Libera qualquer arquivo temporário criado por copy(). Chamado automaticamente quando a requisição termina, se o upload chegou a request.files via with_form_data().

Decoradores de nível de 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 manipulador 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 arquivo são armazenados em buffer via FileUpload.copy(), de modo que o manipulador possa iterar sobre request.files e request.form livremente. Os arquivos temporários são limpos automaticamente quando a requisição termina.

Para uploads maiores do que alguns megabytes, prefira a API de streaming FormDataIter; with_form_data() acumula a requisição inteira na memória ou no sistema de arquivos antes de o manipulador ser executado.