Protobuf til Python-konverter
Lim inn et .proto-skjema. Få Python-dataclasses med type hints, IntEnum-klasser for enums og riktige defaults for repeated- og map-felter.
Inndata (.proto-skjema)
Utdata (Python)
Hva dette verktøyet gjør
Du har et Protocol Buffers-skjema og en Python-tjeneste eller et skript som trenger matchende typer. Den offisielle veien er protoc med Python-pluginen (se den offisielle Python-tutorialen) — den produserer genererte message-klasser som funker, men er ubehagelige å lese og støyende i differ. Dette verktøyet spytter i stedet ut vanlige dataclasses — rene, idiomatiske og lette å mocke i tester. Lim inn skjemaet, kopier utdata, slipp det inn i prosjektet ditt.
Typetilordningen er det du selv ville skrevet for hånd. string/bytes blir til str/bytes, bool blir til bool, hver heltallsbredde (int32 opp til sfixed64) blir til int, og double/float blir til float. repeated T blir til list[T] med field(default_factory=list), map<K, V> blir til dict[K, V] med field(default_factory=dict), og singulære message-referanser blir til Optional[Msg] med default None, slik at sirkulære referanser og forward references bare funker.
Enums blir subklasser av IntEnum, som er det den offisielle protobuf-Python-runtimen bruker internt og det de fleste reviewere forventer å se. from __future__ import annotations ligger på toppen, slik at utsatt evaluering håndterer forward refs rent — ingen streng-siterte type hints i kroppen er nødvendige. Nestede meldinger flates ut til top-level dataclasses; Python får ikke samme gevinst av nesting som Java, og flate navn er enklere å importere. Alt kjører i nettleseren din; ingenting av skjemaet ditt forlater siden.
Slik bruker du det
Tre steg. Utdata er klar til å slippes inn i en <code>.py</code>-fil.
Lim inn .proto-skjemaet ditt
Slipp skjemaet i den venstre editoren. syntax = "proto3"; på toppen er greit men valgfritt. Parseren håndterer nestede message-blokker, enum-deklarasjoner, oneof, map<K, V> og feltvalg. Imports gjenkjennes men hoppes over — lim inn importerte typer inline hvis skjemaet ditt spenner over flere filer.
Feltnavn beholdes som de er: order_id i .proto forblir order_id i Python. snake_case er allerede Pythonic. Klassenavn beholdes også i PascalCase, i tråd med PEP 8-konvensjoner.
Les utdata
Den høyre panelen viser Python med ett @dataclass per melding og én IntEnum-subklasse per enum. Enums først, deretter meldinger i avhengighetsrekkefølge (barn før foreldre). Legg filen til prosjektet ditt, importer dataclassene du trenger, så er du ferdig.
Bruk dataclassene
Konstruer instanser med nøkkelordsargumenter, muter dem som vanlige objekter, serialiser med dataclasses.asdict() eller json.dumps for HTTP-transport. Trenger du fullstendig Protobuf wire-format-koding, plugg dataclassene inn i protobuf-python eller bruk dem som typet shim foran gRPC-klienten din.
Når det faktisk sparer tid
Skissere typer for en ny gRPC Python-tjeneste
Du starter en ny tjeneste som konsumerer et eksisterende Protobuf-API. Du vil ha rene dataclasses for request/response-formene uten å kjøre protoc ennå. Lim inn skjemaet, slipp utdata i types.py, skriv forretningslogikken din mot dataclassene, og koble til gRPC Python senere når du er klar.
Mocke Protobuf-data i pytest
Genererte Protobuf-message-klasser er smertefulle å konstruere i tester fordi hvert felt har sin egen setter, og konstruktørene tar ikke alle felter som kwargs. Håndlagde dataclasses gjør det — Order(order_id="ORD-42", customer_name="Ava Chen", total_amount=99.50) bare funker. Bruk denne utdata som fixtures og mocks, og behold de ekte Protobuf-klassene for wire-format-serialisering.
Gjennomgå en Protobuf-API-endring
En backend-kollega la til felter i Order og en ny OrderStatus-verdi. Du vil vite hva Python-klientkoden din må håndtere uten å kjøre hele byggingen. Lim inn det nye .proto, diff dataclass-utdata mot dine nåværende typer, legg igjen en fokusert gjennomgangskommentar.
Raske skript og engangs-ETL-jobber
Du skriver et 50-linjers skript for å backfille data fra en JSON-dump som følger et Protobuf-skjema. Å sette opp protoc for et engangsskript er overkill. Hent dataclassene herfra, parse JSON-en inn i dem, kjør skriptet, kast det. Ingen byggesteg, ingen toolchain, ingen genererte filer som ligger igjen i repoet.
Vanlige spørsmål
Sendes skjemaet mitt noe sted?
Nei. Parseren og Python-emitteren kjører helt i nettleseren din som JavaScript. Åpne DevTools og se på Network-fanen mens du limer inn — null requests. Nyttig når skjemaet inneholder interne typenavn, pakkestier eller noe annet du helst ikke vil sende til en tredjepartstjeneste.
Hvorfor dataclasses i stedet for de offisielle protobuf-python-message-klassene?
Klassene protoc genererer funker, men er ordrike, vanskelige å mocke i tester og støyende i code review. Dataclasses gir deg typede kwargs, likhetssammenligning og ren repr på kjøpet. Trenger du wire-format-koding, kan du tilordne mellom dataclassene og de offisielle message-typene i et tynt adapterlag — de fleste team synes det er en bedre oppdeling enn å type alt mot de genererte klassene.
Hvorfor IntEnum og ikke str-verdiede enums?
Protobuf-enums er int-verdiede på wire-nivå — hver verdi har et tag-nummer. IntEnum matcher det eksakt: OrderStatus.ORDER_STATUS_PAID er både et navngitt medlem og heltallet 2, som round-tripper rent gjennom JSON eller wire-format. Vil du ha en StrEnum (Python 3.11+) for JSON-kodingen i stedet, gjør find-replace på IntEnum i utdata.
Hvorfor er message-felter Optional[Msg] i stedet for bare Msg?
I proto3 kan et singulært message-felt være usatt (fraværet er meningsfullt, i motsetning til skalarer der default er nullverdien). Default None matcher den semantikken og holder sirkulære referanser kompilerbare — hvis Order bygger inn en Address og adressen bygger inn tilbake, trenger ingen av dataclassene å være definert først. from __future__ import annotations på toppen av filen gjør at forward refs løses i runtime via PEP 563.
Hvordan håndteres map<K, V>?
Rendres som dict[K, V] med field(default_factory=dict) som default. Protobuf-maps med ikke-string-nøkler (map<int32, string>) blir dict[int, str]. JSON har bare string-nøkler, så når du serialiserer dict-en til JSON, blir int-nøklene strings — det er en særegenhet ved proto3 JSON-spec-en, ikke ved konverteren.
Håndterer den oneof?
Hvert oneof-felt sendes ut som et vanlig dataclass-felt. Utdata håndhever ikke "nøyaktig én"-betingelsen — for det ville du trengt en Union-type eller en diskriminert struktur, og det avhenger av hvordan runtimen din modellerer eksklusivitet. Det flate oppsettet er enkelt å lese og matcher det de fleste Python-kodebaser gjør i praksis. Rediger for hånd hvis du vil ha strammere typing.
Relaterte verktøy
Hvis du jobber med Protobuf, JSON og Python, passer disse godt sammen: