Conversor de Protobuf para Python
Cole um esquema .proto. Receba dataclasses Python com type hints, classes IntEnum para enums e defaults adequados para campos repeated e map.
Entrada (esquema .proto)
Saída (Python)
O que esta ferramenta faz
Você tem um esquema Protocol Buffers e um serviço ou script Python que precisa dos tipos correspondentes. O caminho oficial é o protoc com o plugin Python (veja o tutorial oficial de Python), que gera classes de mensagem que funcionam, mas são desconfortáveis de ler e barulhentas em diffs. Esta ferramenta emite dataclasses simples no lugar — limpas, idiomáticas e fáceis de mockar em testes. Cole o esquema, copie a saída, jogue no seu projeto.
O mapeamento de tipos é o que você escreveria à mão. string/bytes viram str/bytes, bool vira bool, qualquer largura de inteiro (int32 até sfixed64) vira int, e double/float viram float. repeated T vira list[T] com field(default_factory=list), map<K, V> vira dict[K, V] com field(default_factory=dict), e referências singulares a mensagens viram Optional[Msg] com default None — assim referências circulares e forward references simplesmente funcionam.
Enums viram subclasses de IntEnum, que é o que o runtime oficial do protobuf em Python usa internamente e o que a maioria dos revisores espera ver. from __future__ import annotations fica no topo para que a avaliação adiada resolva forward refs limpinho — sem precisar de type hints entre aspas no corpo. Mensagens aninhadas são achatadas para dataclasses de nível superior; Python não ganha em aninhar como o Java ganha, e nomes planos são mais fáceis de importar. Tudo roda no seu navegador; nada do seu esquema sai da página.
Como usar
Três passos. A saída está pronta para ir direto para um arquivo <code>.py</code>.
Cole seu esquema .proto
Jogue o esquema no editor da esquerda. syntax = "proto3"; no topo é ok mas opcional. O parser lida com blocos message aninhados, declarações enum, oneof, map<K, V> e opções de campo. Imports são reconhecidos mas ignorados — cole os tipos importados inline se seu esquema cobre vários arquivos.
Os nomes dos campos ficam como estão: order_id em .proto continua order_id em Python. Snake_case já é Pythonic. Os nomes das classes também permanecem em PascalCase, alinhado com as convenções do PEP 8.
Leia a saída
O painel da direita mostra Python com um @dataclass por mensagem e uma subclasse IntEnum por enum. Enums primeiro, depois mensagens em ordem de dependência (filhos antes dos pais). Adicione o arquivo ao seu projeto, importe as dataclasses que precisa e pronto.
Use as dataclasses
Crie instâncias com argumentos nomeados, mute como objetos comuns, serialize com dataclasses.asdict() ou json.dumps para transporte HTTP. Se precisar de codificação completa em wire format do Protobuf, conecte as dataclasses no protobuf-python ou use-as como uma camada tipada na frente do seu cliente gRPC.
Quando isso realmente economiza tempo
Esboçar tipos para um novo serviço gRPC em Python
Você está começando um novo serviço que consome uma API Protobuf existente. Quer dataclasses limpas para os formatos de request/response sem ainda rodar o protoc. Cole o esquema, jogue a saída em types.py, escreva sua lógica de negócio contra as dataclasses e plugue o gRPC Python mais tarde, quando estiver pronto.
Mockar dados de Protobuf em pytest
Classes de mensagem Protobuf geradas são chatas de construir em testes porque cada campo tem seu próprio setter, e os construtores não aceitam todos os campos como kwargs. Dataclasses feitas à mão aceitam — Order(order_id="ORD-42", customer_name="Ava Chen", total_amount=99.50) simplesmente funciona. Use esta saída como fixtures e mocks enquanto mantém as classes Protobuf reais para serialização em wire format.
Revisar uma mudança de API Protobuf
Um colega de backend adicionou campos a Order e um novo valor de OrderStatus. Você quer saber o que seu código cliente em Python precisa lidar sem rodar a build inteira. Cole o novo .proto, faça diff da saída de dataclass contra seus tipos atuais e deixe um comentário de review focado.
Scripts rápidos e ETL pontual
Você está escrevendo um script de 50 linhas para fazer backfill de dados de um dump JSON que segue um esquema Protobuf. Configurar protoc para um script de uso único é exagero. Pegue as dataclasses daqui, parseie o JSON nelas, rode o script e descarte. Sem etapa de build, sem toolchain, sem arquivos gerados sobrando no repositório.
Perguntas comuns
Meu esquema é enviado para algum lugar?
Não. O parser e o emissor Python rodam inteiramente no seu navegador como JavaScript. Abra o DevTools e fique de olho na aba Network enquanto cola — zero requisições. Útil quando seu esquema tem nomes de tipos internos, caminhos de pacote, ou qualquer coisa que você prefere não mandar para um serviço de terceiros.
Por que dataclasses em vez das classes oficiais do protobuf-python?
As classes geradas pelo protoc funcionam, mas são verbosas, difíceis de mockar em testes e barulhentas em code review. Dataclasses te dão kwargs tipados, comparação de igualdade e repr limpo de graça. Se precisar de codificação em wire format, dá para mapear entre as dataclasses e os tipos de mensagem oficiais em uma camada de adaptador fina — a maioria dos times acha essa divisão melhor do que tipar tudo contra as classes geradas.
Por que IntEnum e não enums com valor str?
Enums Protobuf são int no nível do wire — todo valor tem um número de tag. IntEnum casa exatamente com isso: OrderStatus.ORDER_STATUS_PAID é tanto um membro nomeado quanto o inteiro 2, que faz round-trip limpo via JSON ou wire format. Se quiser um StrEnum (Python 3.11+) para a codificação JSON, é só fazer find-replace de IntEnum na saída.
Por que campos de mensagem são Optional[Msg] em vez de só Msg?
Em proto3 um campo singular de mensagem pode ficar não definido (a ausência tem significado, ao contrário de escalares onde o default é o valor zero). Ter None como default casa com essa semântica e mantém referências circulares compilando — se Order embute um Address e o address embute de volta, nenhuma das dataclasses precisa que a outra esteja definida primeiro. from __future__ import annotations no topo do arquivo faz com que os forward refs sejam resolvidos em tempo de execução via PEP 563.
Como ele lida com map<K, V>?
Renderiza como dict[K, V] com field(default_factory=dict) de default. Maps Protobuf com chaves não-string (map<int32, string>) viram dict[int, str]. JSON só tem chaves string, então quando você serializa o dict para JSON as chaves int viram strings — isso é uma peculiaridade da spec JSON do proto3, não do conversor.
Lida com oneof?
Cada campo de oneof é emitido como um campo de dataclass comum. A saída não impõe a restrição de "exatamente um" — para isso você ia querer um tipo Union ou uma estrutura discriminada, o que depende de como seu runtime modela exclusividade. O layout plano é fácil de ler e bate com o que a maioria das bases de código Python faz na prática. Edite à mão se precisar de tipagem mais rígida.
Ferramentas relacionadas
Se você trabalha com Protobuf, JSON e Python, estas combinam bem: