microdot.multipart — parsing di multipart/form-data

Esegue il parsing dei corpi di richiesta Content-Type: multipart/form-data – la codifica che i browser utilizzano per i form che includono campi <input type="file">. Due varianti di API:

  • Un FormDataIter in streaming che restituisce i campi uno alla volta – utile quando l’applicazione deve gestire upload molto grandi pezzo per pezzo su un dispositivo con memoria limitata.

  • Un decoratore with_form_data() che bufferizza tutto e popola request.form / request.files – l’API comoda per gli upload di dimensioni normali.

class FormDataIter

class microdot.multipart.FormDataIter(request)

Iteratore asincrono sulle parti del corpo multipart di request. I valori restituiti sono tuple (name, value); value è una str per i campi regolari e un FileUpload per i campi file.

Utilizzato direttamente quando la memoria conta più dell’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

Quando si itera sui campi file, il file deve essere consumato (tramite FileUpload.read() o FileUpload.save()) prima della successiva iterazione async for – lo stream sottostante viene invalidato quando l’iterazione avanza.

buffer_size: int

Attributo di classe. Dimensione del chunk utilizzato durante la lettura dallo stream della richiesta. Predefinito 256 byte. Aumentalo per un throughput maggiore a costo di un maggiore consumo di RAM.

class FileUpload

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

Un singolo file caricato. Le istanze vengono restituite da FormDataIter e raccolte in request.files da with_form_data(). Le applicazioni normalmente non costruiscono FileUpload direttamente.

filename: str

Il nome originale del file così come inviato dal client (non attendibile – non passarlo a open() senza sanitizzarlo).

content_type: str | None

Il tipo MIME dall’header Content-Type della parte, oppure None se non fornito.

max_memory_size: int

Attributo di classe. Soglia (in byte) oltre la quale copy() passa dal buffering in memoria a un file temporaneo. Predefinito 1024.

async read(n: int = -1)

Legge fino a n byte dallo stream dell’upload. -1 legge fino alla fine.

async save(path_or_file)

Salva l’upload in path_or_file, che può essere un percorso del filesystem oppure un oggetto file già aperto.

async copy(max_memory_size: int | None = None)

Bufferizza l’upload (in RAM oppure in un file temporaneo, a seconda di max_memory_size) in modo che il resto del corpo multipart possa essere analizzato senza che lo stream originale venga invalidato. Il decoratore with_form_data() lo chiama automaticamente.

async close()

Rilascia qualsiasi file temporaneo creato da copy(). Chiamato automaticamente al termine della richiesta se l’upload ha raggiunto request.files tramite with_form_data().

Decoratori a livello di modulo

microdot.multipart.with_form_data(f)

Decoratore che esegue il parsing del corpo multipart in anticipo e popola request.form e request.files prima dell’esecuzione dell’handler:

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'

Gli upload di file vengono bufferizzati tramite FileUpload.copy(), in modo che l’handler possa iterare liberamente request.files e request.form. I file temporanei vengono ripuliti automaticamente al termine della richiesta.

Per upload più grandi di un paio di megabyte, preferisci l’API in streaming FormDataIter; with_form_data() accumula l’intera richiesta in memoria o sul filesystem prima dell’esecuzione dell’handler.