Protobuf-zu-Python-Konverter
Füge ein .proto-Schema ein. Du bekommst Python-Dataclasses mit Type Hints, IntEnum-Klassen für Enums und passende Defaults für repeated- und map-Felder.
Eingabe (.proto-Schema)
Ausgabe (Python)
Was dieses Tool macht
Du hast ein Protocol Buffers-Schema und einen Python-Service oder ein Skript, das passende Typen braucht. Der offizielle Weg ist protoc mit dem Python-Plugin (siehe das offizielle Python-Tutorial) — die generierten Message-Klassen funktionieren, sind aber unangenehm zu lesen und laut in Diffs. Dieses Tool gibt stattdessen einfache Dataclasses aus — sauber, idiomatisch und in Tests leicht zu mocken. Schema einfügen, Output kopieren, ins Projekt fallen lassen.
Das Type-Mapping ist genau das, was du von Hand schreiben würdest. string/bytes werden zu str/bytes, bool zu bool, jede Integer-Breite (int32 bis sfixed64) zu int, und double/float zu float. repeated T wird zu list[T] mit field(default_factory=list), map<K, V> zu dict[K, V] mit field(default_factory=dict), und einzelne Message-Referenzen werden zu Optional[Msg] mit Default None, sodass zirkuläre und Forward-Referenzen einfach laufen.
Enums werden zu Subklassen von IntEnum — das nutzt das offizielle protobuf-Python-Runtime intern und das erwarten die meisten Reviewer zu sehen. from __future__ import annotations steht oben, damit die verzögerte Auswertung Forward-Refs sauber abhandelt — keine string-quoted Type Hints im Body nötig. Verschachtelte Messages werden zu Top-Level-Dataclasses geflattened; Python profitiert von Verschachtelung nicht so wie Java, und flache Namen lassen sich einfacher importieren. Alles läuft im Browser; nichts vom Schema verlässt die Seite.
So nutzt du es
Drei Schritte. Die Ausgabe lässt sich direkt in eine <code>.py</code>-Datei droppen.
Füge dein .proto-Schema ein
Lass das Schema in den linken Editor fallen. syntax = "proto3"; oben ist okay, aber optional. Der Parser kann verschachtelte message-Blöcke, enum-Deklarationen, oneof, map<K, V> und Feld-Optionen. Imports werden erkannt, aber übersprungen — füge importierte Typen inline ein, falls dein Schema mehrere Dateien umfasst.
Feldnamen bleiben wie sie sind: order_id in .proto bleibt order_id in Python. snake_case ist sowieso schon pythonisch. Klassennamen bleiben in PascalCase, passend zu PEP-8-Konventionen.
Lies die Ausgabe
Das rechte Panel zeigt Python mit einem @dataclass pro Message und einer IntEnum-Subklasse pro Enum. Erst die Enums, dann die Messages in Abhängigkeitsreihenfolge (Kinder vor Eltern). Datei zum Projekt hinzufügen, die nötigen Dataclasses importieren, fertig.
Nutze die Dataclasses
Erzeuge Instanzen mit Keyword-Argumenten, mutiere sie wie normale Objekte, serialisiere mit dataclasses.asdict() oder json.dumps für HTTP-Transport. Wenn du volles Protobuf-Wire-Format-Encoding brauchst, bring die Dataclasses in protobuf-python ein oder nutze sie als getypten Shim vor deinem gRPC-Client.
Wann es wirklich Zeit spart
Typen für einen neuen gRPC-Python-Service skizzieren
Du startest einen neuen Service, der eine bestehende Protobuf-API konsumiert. Du willst saubere Dataclasses für die Request/Response-Formen, ohne schon protoc zu starten. Schema einfügen, Output in types.py droppen, Business-Logik gegen die Dataclasses schreiben, später gRPC Python dranhängen, wenn du soweit bist.
Protobuf-Daten in pytest mocken
Generierte Protobuf-Message-Klassen sind in Tests mühsam zu konstruieren, weil jedes Feld seinen eigenen Setter hat und die Konstruktoren nicht alle Felder als kwargs nehmen. Hand-gerollte Dataclasses tun das — Order(order_id="ORD-42", customer_name="Ava Chen", total_amount=99.50) funktioniert einfach. Nimm diese Ausgabe als Fixtures und Mocks und behalte die echten Protobuf-Klassen für Wire-Format-Serialisierung.
Eine Protobuf-API-Änderung reviewen
Ein Backend-Kollege hat Order Felder hinzugefügt und einen neuen OrderStatus-Wert. Du willst wissen, was dein Python-Client-Code abfangen muss, ohne den vollen Build zu ziehen. Neues .proto einfügen, Dataclass-Output gegen deine aktuellen Typen diffen, fokussierten Review-Kommentar hinterlassen.
Schnelle Skripte und einmalige ETL-Jobs
Du schreibst ein 50-Zeilen-Skript, um Daten aus einem JSON-Dump nachzuladen, das einem Protobuf-Schema folgt. protoc für ein Einmal-Skript aufzusetzen ist Overkill. Hol dir die Dataclasses hier, parse das JSON in sie, lass das Skript laufen, wirf es weg. Kein Build-Schritt, keine Toolchain, keine generierten Dateien, die im Repo herumliegen.
Häufige Fragen
Wird mein Schema irgendwohin geschickt?
Nein. Parser und Python-Emitter laufen vollständig im Browser als JavaScript. Öffne die DevTools und beobachte den Network-Tab beim Einfügen — null Requests. Praktisch, wenn dein Schema interne Typnamen, Package-Pfade oder andere Dinge enthält, die du lieber nicht zu einem Drittanbieter schickst.
Warum Dataclasses statt der offiziellen protobuf-python-Message-Klassen?
Die von protoc generierten Klassen funktionieren, sind aber wortreich, schwer in Tests zu mocken und laut im Code-Review. Dataclasses geben dir getypte kwargs, Gleichheitsvergleich und sauberen repr gratis. Brauchst du Wire-Format-Encoding, kannst du in einem dünnen Adapter-Layer zwischen den Dataclasses und den offiziellen Message-Typen mappen — die meisten Teams finden diese Trennung besser, als alles gegen die generierten Klassen zu typisieren.
Warum IntEnum und keine Enums mit str-Wert?
Protobuf-Enums sind auf Wire-Ebene int-wertig — jeder Wert hat eine Tag-Nummer. IntEnum deckt das exakt ab: OrderStatus.ORDER_STATUS_PAID ist gleichzeitig benanntes Member und die Ganzzahl 2 und macht einen sauberen Round-Trip durch JSON oder Wire-Format. Wenn du ein StrEnum (Python 3.11+) für die JSON-Codierung willst, mach im Output ein Find-Replace auf IntEnum.
Warum sind Message-Felder Optional[Msg] statt einfach Msg?
In proto3 kann ein einzelnes Message-Feld unset sein (das Fehlen ist bedeutungstragend, anders als bei Skalaren, wo der Default der Nullwert ist). Ein None-Default passt zu dieser Semantik und hält zirkuläre Referenzen kompilierbar — wenn Order ein Address einbettet und das Address zurück, muss keine der Dataclasses zuerst definiert sein. from __future__ import annotations oben in der Datei sorgt via PEP 563 dafür, dass Forward-Refs zur Laufzeit aufgelöst werden.
Wie wird map<K, V> behandelt?
Wird als dict[K, V] mit field(default_factory=dict) als Default ausgegeben. Protobuf-Maps mit Nicht-String-Schlüsseln (map<int32, string>) werden zu dict[int, str]. JSON kennt nur String-Schlüssel, also werden int-Schlüssel beim Serialisieren zu Strings — das ist eine Eigenheit der proto3-JSON-Spec, nicht des Konverters.
Wird oneof unterstützt?
Jedes oneof-Feld wird als reguläres Dataclass-Feld ausgegeben. Die Ausgabe erzwingt die "genau eins"-Bedingung nicht — dafür bräuchtest du einen Union-Typ oder eine diskriminierte Struktur, was davon abhängt, wie dein Runtime Exklusivität modelliert. Das flache Layout liest sich gut und entspricht dem, was die meisten Python-Codebases in der Praxis tun. Wenn du strengere Typisierung brauchst, editiere von Hand.
Verwandte Tools
Wenn du mit Protobuf, JSON und Python arbeitest, passen diese gut zusammen: