Python SDK 2.0: suporte a asyncio e Python 3.12+
A versão 2.0.0 do nosso SDK para Python, pytransloadit, adiciona
AsyncTransloadit, um cliente asyncio que convive com o cliente síncrono que você já usa.
Ela também aumenta a versão mínima do Python para 3.12.
A seguir, mostramos para que serve o cliente assíncrono e o que verificar antes de migrar da 1.x.
Por que um cliente assíncrono
O cliente 1.x se comunica com nossa API pelo Requests, que é bloqueante. Em um app FastAPI ou aiohttp, cada chamada a esse cliente bloqueia o loop de eventos. Enquanto uma requisição espera uma Assembly terminar, outras requisições nesse processo worker também esperam, a menos que você transfira a chamada para um pool de threads por conta própria.
AsyncTransloadit envia suas chamadas de API pelo aiohttp e consulta periodicamente o
status das Assemblies com asyncio.sleep, permitindo que você aguarde uma Assembly
com await, como qualquer outra operação de E/S. Isso também facilita a
execução de várias Assemblies ao mesmo tempo em um script ou processo worker em segundo plano.
Processar arquivos simultaneamente
Instale a versão 2.0 no Python 3.12 ou mais recente:
python -m pip install --upgrade 'pytransloadit>=2,<3'
Este script redimensiona três fotos em paralelo com
🤖 /image/resize, compartilhando um cliente e uma sessão HTTP. Ele lê
suas credenciais de TRANSLOADIT_KEY e TRANSLOADIT_SECRET:
import asyncio
import os
from transloadit.async_client import AsyncTransloadit
async def resize(client, path):
assembly = client.new_assembly()
thumb = {"use": ":original", "width": 400}
assembly.add_step("thumb", "/image/resize", thumb)
with open(path, "rb") as upload:
assembly.add_file(upload)
response = await assembly.create(wait=True, resumable=False)
if "error" in response.data:
raise RuntimeError(f"{path}: {response.data['error']}")
return response.data["results"]["thumb"][0]["ssl_url"]
async def main():
paths = ["chameleon.jpg", "prinsengracht.jpg", "desert.jpg"]
key = os.environ["TRANSLOADIT_KEY"]
secret = os.environ["TRANSLOADIT_SECRET"]
async with AsyncTransloadit(key, secret) as client:
urls = await asyncio.gather(*(resize(client, p) for p in paths))
print("\n".join(urls))
asyncio.run(main())
Baixe as fotos de exemplo e execute o script:
for photo in chameleon prinsengracht desert; do
curl -fsSLo "$photo.jpg" \
"https://demos.transloadit.com/inputs/$photo.jpg"
done
python resize_many.py
O script imprime uma URL por miniatura. Na nossa máquina, as três Assemblies (25 MB de fotos) terminaram em cerca de 3 segundos, contra cerca de 8 segundos para o mesmo loop com o cliente síncrono.
wait=True retorna quando a Assembly termina. Os erros da API continuam vindo na
resposta, por isso o script verifica error. resumable=False
envia cada arquivo na requisição de criação. Para arquivos grandes, mantenha o valor padrão de
True: os uploads retomáveis usam tus, que o SDK executa em threads de
processamento, para que o loop de eventos continue respondendo durante os uploads.
Usar no FastAPI
Instale o FastAPI, o Uvicorn e o parser multipart de que o FastAPI precisa para uploads:
python -m pip install fastapi uvicorn python-multipart
Crie o cliente uma vez por app e compartilhe-o entre as requisições:
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, UploadFile
from transloadit.async_client import AsyncTransloadit
@asynccontextmanager
async def lifespan(app: FastAPI):
key = os.environ["TRANSLOADIT_KEY"]
secret = os.environ["TRANSLOADIT_SECRET"]
async with AsyncTransloadit(key, secret) as client:
app.state.transloadit = client
yield
app = FastAPI(lifespan=lifespan)
@app.post("/thumbnails")
async def create_thumbnail(file: UploadFile):
assembly = app.state.transloadit.new_assembly()
thumb = {"use": ":original", "width": 400}
assembly.add_step("thumb", "/image/resize", thumb)
assembly.add_file(file.file)
response = await assembly.create(wait=True, resumable=False)
thumbs = response.data.get("results", {}).get("thumb")
if "error" in response.data or not thumbs:
raise HTTPException(502, "Could not create a thumbnail")
return {"url": thumbs[0]["ssl_url"]}
uvicorn app:app
curl -fsSL -F file=@chameleon.jpg http://127.0.0.1:8000/thumbnails
Enviamos três uploads ao mesmo tempo para esse endpoint, e um processo worker do Uvicorn respondeu aos três
em menos de 4 segundos. Esperar pelo resultado dentro da requisição é adequado para tarefas rápidas de
imagem. Para vídeo e outros processamentos demorados, crie a Assembly sem
wait=True e passe um notify_url para
new_assembly(), para que a Transloadit
chame seu app quando a tarefa terminar.
O que o cliente assíncrono abrange
AsyncTransloadit oferece os mesmos recursos do cliente síncrono: criar, consultar,
listar e cancelar Assemblies, gerenciar Templates,
consultar o faturamento mensal e assinar URLs do Smart CDN. Use await
nos métodos que acessam a rede. new_assembly(),
new_template() e get_signed_smart_cdn_url() continuam síncronos.
Use o cliente com async with ou chame await client.aclose() ao terminar.
Você pode passar sua própria sessão aiohttp com session=. Porém, as
transferências retomáveis não usam essa sessão, então as configurações de proxy e TLS dela não se
aplicam a essas transferências. Configure essas opções pelo ambiente do Requests.
Migrar da 1.x
Seu código síncrono continua funcionando: from transloadit import client e seus métodos não mudaram
na versão 2.0. Veja o que você precisa verificar:
- Python 3.12 ou mais recente. Primeiro, atualize os interpretadores dos seus ambientes de
desenvolvimento, CI e implantação. No Python 3.9 a 3.11, o pip continua instalando a versão 1.0.4,
a versão mais recente da série 1.x. Fixe
pytransloadit<2para deixar isso explícito. - Versões mínimas das dependências. A versão 2.0 exige
requests>=2.33,<3eurllib3>=2.7,<3. Flexibilize as versões antigas fixadas nas suas restrições e gere novamente o arquivo de lock. - Redirecionamentos. Os redirecionamentos HTTP são retornados para você em vez de serem seguidos.
- Validação de entrada. URLs de serviço inválidas e IDs de Template vazios geram
ValueError. - Templates. Ao combinar uma opção
templatecomadd_step(), passe o valor detemplatecomo dict, e não como string JSON. - Respostas. Uma resposta que não seja JSON coloca texto ou bytes em
Response.data, e um corpo vazio resulta em uma string vazia. - Consulta periódica. Com
wait=True, esgotar as tentativas nas consultas de status sujeitas a limites de requisições geraAssemblyPollingError. A Assembly ainda pode estar em execução: use oassembly_urldo erro para consultar novamente ou cancelá-la. - URLs de Assembly. As requisições de status e cancelamento só são enviadas a URLs de Assembly confiáveis, e o cliente padrão rejeita outros hosts.
- Smart CDN. Os parâmetros booleanos são assinados como
trueefalse, seguindo nossa implementação de referência em Node.js. Os slugs de Workspace devem ser válidos para DNS, eauth_key,expesigsão chaves de consulta reservadas.
O README e o registro de alterações da versão 2.0.0 contêm todas as notas de migração.
Começar
python -m pip install --upgrade 'pytransloadit>=2,<3'
Encontre o pacote no PyPI, scripts síncronos e assíncronos executáveis na pasta de exemplos e a referência da API no Read the Docs. Nossa documentação do SDK para Python aborda os conceitos básicos. Ainda não tem uma conta? Cadastre-se gratuitamente e você poderá executar os exemplos acima em poucos minutos. No plano Community gratuito, os resultados de imagem recebem marca-d’água; nossas perguntas frequentes explicam por quê. Envie dúvidas ou problemas com a migração ao rastreador de problemas do python-sdk.
