Input (.proto-skema)

Output (Python)

Hvad værktøjet gør

Du har et Protocol Buffers-skema og en Python-tjeneste eller et script, der skal bruge tilsvarende typer. Den officielle vej er protoc med Python-pluginet (se den officielle Python-tutorial) — den producerer genererede message-klasser, der virker, men er ubekvemme at læse og støjende i diffs. Dette værktøj udsender i stedet rene dataclasses — rene, idiomatiske og lette at mocke i tests. Indsæt skemaet, kopiér output, smid det ind i dit projekt.

Type-mapningen er præcis det, du selv ville skrive i hånden. string/bytes bliver til str/bytes, bool bliver til bool, alle heltalsbredder (int32 op til sfixed64) bliver til int, og double/float bliver til float. repeated T bliver til list[T] med field(default_factory=list), map<K, V> bliver til dict[K, V] med field(default_factory=dict), og singulære message-referencer bliver til Optional[Msg] med default None, så cirkulære referencer og forward references bare virker.

Enums bliver subklasser af IntEnum, hvilket er det den officielle protobuf-Python-runtime bruger internt og det de fleste reviewere forventer at se. from __future__ import annotations ligger øverst, så udskudt evaluering klarer forward refs pænt — ingen citerede type hints i kroppen er nødvendige. Indlejrede messages flades ud til top-level dataclasses; Python får ikke samme gevinst af nesting som Java, og flade navne er nemmere at importere. Alt kører i din browser; intet af dit skema forlader siden.

Sådan bruger du det

Tre trin. Output er klar til at smide ind i en <code>.py</code>-fil.

1

Indsæt dit .proto-skema

Smid skemaet ind i editoren til venstre. syntax = "proto3"; øverst er fint men valgfrit. Parseren håndterer indlejrede message-blokke, enum-erklæringer, oneof, map<K, V> og field options. Imports genkendes men springes over — indsæt importerede typer inline, hvis dit skema spænder over flere filer.

Feltnavne bevares som de er: order_id i .proto forbliver order_id i Python. snake_case er allerede Pythonic. Klassenavne bevares også i PascalCase, i tråd med PEP 8-konventioner.

2

Læs output

Højre panel viser Python med ét @dataclass pr. message og én IntEnum-subklasse pr. enum. Enums først, derefter messages i afhængighedsrækkefølge (børn før forældre). Tilføj filen til dit projekt, importér de dataclasses du har brug for, og du er færdig.

3

Brug dataclasserne

Konstruér instanser med keyword-argumenter, mutér dem som almindelige objekter, serialisér med dataclasses.asdict() eller json.dumps til HTTP-transport. Hvis du har brug for fuld Protobuf wire-format-encoding, så slå dataclasserne sammen med protobuf-python eller brug dem som typed shim foran din gRPC-klient.

Hvornår det reelt sparer tid

Skitsere typer til en ny gRPC Python-tjeneste

Du starter en ny tjeneste, der konsumerer en eksisterende Protobuf-API. Du vil have rene dataclasses til request/response-formerne uden at køre protoc endnu. Indsæt skemaet, smid output i types.py, skriv din forretningslogik mod dataclasserne, og hægt gRPC Python på senere, når du er klar.

Mocke Protobuf-data i pytest

Genererede Protobuf-message-klasser er besværlige at konstruere i tests, fordi hvert felt har sin egen setter, og constructors ikke tager alle felter som kwargs. Håndlavede dataclasses gør — Order(order_id="ORD-42", customer_name="Ava Chen", total_amount=99.50) virker bare. Brug dette output som fixtures og mocks og hold de rigtige Protobuf-klasser til wire-format-serialisering.

Reviewe en Protobuf-API-ændring

En backend-kollega har tilføjet felter til Order og en ny OrderStatus-værdi. Du vil vide, hvad din Python-klientkode skal håndtere uden at køre den fulde build. Indsæt det nye .proto, lav en diff af dataclass-output mod dine nuværende typer og efterlad en fokuseret review-kommentar.

Hurtige scripts og engangs-ETL-jobs

Du skriver et 50-linjers script til at backfilde data fra et JSON-dump, der følger et Protobuf-skema. At sætte protoc op til et engangsscript er overkill. Tag dataclasserne herfra, parse JSON ind i dem, kør scriptet, smid det væk. Intet build-trin, ingen toolchain, ingen genererede filer, der ligger og roder i repoet.

Almindelige spørgsmål

Bliver mit skema sendt nogen steder hen?

Nej. Parseren og Python-emitteren kører fuldt ud i din browser som JavaScript. Åbn DevTools og hold øje med Network-fanen mens du indsætter — nul requests. Nyttigt når dit skema indeholder interne typenavne, package-stier eller noget, du helst ikke vil sende til en tredjepartstjeneste.

Hvorfor dataclasses i stedet for de officielle protobuf-python-message-klasser?

Klasserne genereret af protoc virker, men er ordrige, svære at mocke i tests og støjende i code review. Dataclasses giver dig typede kwargs, ligheds-sammenligning og pæn repr gratis. Hvis du skal bruge wire-format-encoding, kan du mappe mellem dataclasserne og de officielle message-typer i et tyndt adapter-lag — de fleste teams synes, det er en bedre opdeling end at type alt mod de genererede klasser.

Hvorfor IntEnum og ikke str-værdiede enums?

Protobuf-enums er int-værdiede på wire-niveau — hver værdi har et tag-nummer. IntEnum matcher præcis det: OrderStatus.ORDER_STATUS_PAID er både et navngivet medlem og heltallet 2, der round-tripper rent via JSON eller wire format. Vil du have en StrEnum (Python 3.11+) til JSON-encodingen i stedet, så lav find-replace på IntEnum i output.

Hvorfor er message-felter Optional[Msg] i stedet for bare Msg?

I proto3 kan et singulært message-felt være usat (fraværet er betydningsfuldt, modsat skalarer hvor default er nulværdien). Default None matcher den semantik og holder cirkulære referencer kompilérbare — hvis Order indlejrer en Address og address indlejrer tilbage, behøver ingen af dataclasserne at være defineret først. from __future__ import annotations øverst i filen gør at forward refs løses i runtime via PEP 563.

Hvordan håndteres map<K, V>?

Renderes som dict[K, V] med field(default_factory=dict) som default. Protobuf-maps med ikke-string-nøgler (map<int32, string>) bliver til dict[int, str]. JSON har kun string-nøgler, så når du serialiserer dict’en til JSON, bliver int-nøglerne til strings — det er en særhed ved proto3 JSON-spec’en, ikke ved konverteren.

Håndterer den oneof?

Hvert oneof-felt emitteres som et almindeligt dataclass-felt. Output håndhæver ikke "præcis én"-betingelsen — til det ville du have brug for en Union-type eller en diskrimineret struktur, og det afhænger af, hvordan din runtime modellerer eksklusivitet. Det flade layout er let at læse og matcher det, de fleste Python-kodebaser gør i praksis. Rediger i hånden, hvis du vil have strammere typning.

Relaterede værktøjer

Hvis du arbejder med Protobuf, JSON og Python, passer disse godt sammen: