SDK
Arquivos e pastas
Suba, liste e baixe DICOM, imagens, vídeo e PDFs cifrados ponta a ponta com o SDK diagnos, em pastas e ligados a exames.
English · Português (Brasil)
vault.drives guarda séries DICOM, imagens, vídeo e PDFs cifrados ponta a ponta, em pastas e ligados a exames. Cada
arquivo ganha a própria chave; o nome, o conteúdo e a cifragem própria da camada de armazenamento são selados
exatamente como o app web os sela, então um arquivo subido aqui abre no app web e vice-versa. O modelo — nós, grupos,
pendente e pronto — está em Conceitos.
Subir#
Um drive é o conjunto de arquivos de um security group. Gravar precisa de um; ler só precisa do id do nó.
from diagnos import Diagnos
vault = Diagnos()
drive = vault.drives.drive("sg_oncology")
node = drive.upload("scans/IM-0001.dcm") # nome e tipo MIME a partir do path
print(node.node_id, node.status, node.mime_type, node.size)
note = drive.upload(b"bytes crus tambem funcionam", name="nota.txt") # bytes precisam de nome
with open("report.pdf", "rb") as handle:
pdf = drive.upload(handle) # um arquivo aberto: o nome vem do handle
| Argumento | Padrão | |
|---|---|---|
name |
o nome de arquivo do path (ou do arquivo aberto) | obrigatório para bytes e streams anônimos; selado |
mime_type |
adivinhado pelo nome; .dcm é application/dicom |
enviado em claro — é como o cofre classifica DICOM, imagem e vídeo |
exam_id |
nenhum | liga o arquivo a um exame |
parent_id |
nenhum | a pasta onde colocá-lo |
upload() retorna quando o arquivo está confirmado: o nó está ready.
Dica
Passe um path ou bytes quando puder. O tamanho precisa ser conhecido antes de cifrar — o cofre assina cada upload
para um número exato de bytes — então qualquer outro stream é antes copiado para um arquivo temporário, em texto
claro, e removido depois do upload.
Vários arquivos de uma vez#
from diagnos import UploadSource
folder_id = drive.create_folder("TC 2026-09-01")
nodes = drive.upload_many(
["scans/IM-0001.dcm", "scans/IM-0002.dcm", UploadSource(b"...", name="notas-da-serie.txt")],
parent_id=folder_id,
)
print([drive.name_of(node) for node in nodes]) # na ordem de entrada, todos prontos
upload_many reserva até 100 arquivos por ida e volta e devolve os nós na ordem de entrada. Ele bloqueia até cada
lote terminar; ainda não existe callback de progresso por byte.
Como arquivos grandes viajam#
Você nunca escolhe; o cofre escolhe, pelo tamanho:
| Tamanho | Como sobe |
|---|---|
| até 64 MiB | um PUT assinado, confirmado junto com o resto do lote |
| acima de 64 MiB, até 50 GiB | partes de 32 MiB, assinadas em ondas de até 200 conforme o upload avança |
Um upload multipart que falha no meio é abortado, para o cofre liberar o espaço reservado na hora; uma reserva abandonada expira depois de 6 horas. O corpo é cifrado em frames de 1 MiB enquanto flui, então a memória fica estável qualquer que seja o tamanho do arquivo. O PROTOCOL.pt-BR.md §9 tem o layout dos bytes.
Pastas#
series = drive.create_folder("Série 2", parent_id=folder_id) # aninhada
drive.upload("scans/IM-0002.dcm", parent_id=series)
create_folder devolve o id do nó da pasta nova. O cofre só vê nomes selados, então não distingue duas pastas com o
mesmo nome: chamar duas vezes cria duas pastas. Pastas ficam prontas na hora — não têm conteúdo.
Listar#
for child in drive.iter_all(parent_id=folder_id): # uma pasta deste grupo
print(drive.name_of(child), child.kind, child.size)
for item in vault.drives.iter_all(include_pending=True): # todo grupo que esta sessão pode listar
print(item.security_group_id, item.status, item.node_id)
page = vault.drives.list(security_group="sg_oncology", limit=50) # uma página
drive.list()/iter_all() percorrem um grupo; vault.drives.list()/iter_all() percorrem todo grupo que esta
sessão pode listar, filtrados por security_group, exam_id, parent_id ou include_pending. As linhas são
DriveNodes — só metadado. Os nomes ficam selados até você pedir: name_of(node) abre um, então uma página de mil
arquivos não custa nenhuma decifragem que você não quis.
Aviso
Um nome é o que quem subiu selou, e o app web sela um caminho relativo ali (exames/2026/IM-0001.dcm). Nunca o
use como caminho local do jeito que vem: pegue o último segmento, como a CLI e a API fazem.
vault.drives.get(node_id) devolve o metadado de um arquivo pronto; uma pasta ou um upload pendente responde
NotFoundError — não há nada para baixar.
Baixar#
data = vault.drives.download(node.node_id) # o arquivo inteiro, decifrado, na RAM
vault.drives.download(node.node_id, "IM-0001.dcm") # direto para um arquivo, um pedaço na RAM por vez
with open("copia.dcm", "wb") as out:
for chunk in vault.drives.iter_download(node.node_id): # faça o stream você mesmo
out.write(chunk)
iter_download decifra de forma preguiçosa: os primeiros bytes chegam a você antes de os últimos saírem do
armazenamento, e nada maior que um frame de 1 MiB fica guardado. Todo frame é autenticado; um arquivo adulterado ou
truncado lança CryptoError em vez de devolver bytes danificados.
O que o cofre vê de um arquivo#
O id do nó, o grupo, o exame e a pasta a que está ligado, o tipo MIME, o tamanho (do corpo cifrado, que o cofre mede e cobra) e os horários. Nunca o nome, nunca o conteúdo. A lista completa está no modelo de segurança.
O que ainda não está aqui#
- Apagar, mover e renomear ainda não têm rota externa.
- Miniaturas e transcodificações para a web (
optimized_variants) só são produzidas para arquivos cuja chave também é custodiada para o processador de mídia do cofre, o que nem o app web nem o SDK fazem hoje. - Sem callback de progresso por byte.
Detalhes e as questões ainda abertas do lado do cofre: COMPATIBILITY.pt-BR.md.