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.

1

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.

2

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.

3

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: