Konwerter Protobuf do Python
Wklej schemat .proto. Dostaniesz dataclasses Pythona z type hints, klasy IntEnum dla enumów oraz właściwe wartości domyślne dla pól repeated i map.
Wejście (schemat .proto)
Wyjście (Python)
Co robi to narzędzie
Masz schemat Protocol Buffers i serwis lub skrypt w Pythonie, który potrzebuje pasujących typów. Oficjalna droga to protoc z pluginem Python (zobacz oficjalny tutorial Python) — generowane klasy wiadomości działają, ale są niewygodne do czytania i głośne w diffach. To narzędzie zamiast tego emituje zwykłe dataclasses — czyste, idiomatyczne i łatwe do mockowania w testach. Wklej schemat, skopiuj wynik, wrzuć do projektu.
Mapowanie typów jest takie, jakie napisałbyś ręcznie. string/bytes stają się str/bytes, bool staje się bool, każda szerokość integera (int32 aż do sfixed64) staje się int, a double/float stają się float. repeated T staje się list[T] z field(default_factory=list), map<K, V> staje się dict[K, V] z field(default_factory=dict), a pojedyncze referencje do wiadomości stają się Optional[Msg] z domyślną wartością None — dzięki czemu referencje cykliczne i forward references po prostu działają.
Enumy stają się podklasami IntEnum — tego używa wewnętrznie oficjalny runtime protobuf w Pythonie i tego oczekuje większość recenzentów kodu. from __future__ import annotations siedzi na górze, żeby odroczone wartościowanie czysto załatwiło forward refs — w ciele nie potrzeba type hintów w cudzysłowach. Zagnieżdżone wiadomości są spłaszczane do dataclasses na poziomie modułu; Python nie zyskuje na zagnieżdżaniu jak Java, a płaskie nazwy łatwiej importować. Wszystko działa w przeglądarce; nic z twojego schematu nie opuszcza strony.
Jak tego używać
Trzy kroki. Wynik jest gotowy do wrzucenia do pliku <code>.py</code>.
Wklej swój schemat .proto
Wrzuć schemat do edytora po lewej. syntax = "proto3"; na górze jest ok, ale opcjonalne. Parser obsługuje zagnieżdżone bloki message, deklaracje enum, oneof, map<K, V> oraz opcje pól. Importy są rozpoznawane, ale pomijane — jeśli twój schemat rozłożony jest na wiele plików, wklej importowane typy inline.
Nazwy pól zostają takie, jakie były: order_id w .proto pozostaje order_id w Pythonie. snake_case już jest pythonic. Nazwy klas też zostają w PascalCase, zgodnie z konwencjami PEP 8.
Przeczytaj wynik
Prawy panel pokazuje Pythona z jednym @dataclass na wiadomość i jedną podklasą IntEnum na enum. Najpierw enumy, potem wiadomości w kolejności zależności (dzieci przed rodzicami). Dodaj plik do projektu, zaimportuj potrzebne dataclasses i gotowe.
Używaj dataclasses
Twórz instancje argumentami nazwanymi, modyfikuj jak normalne obiekty, serializuj dataclasses.asdict() lub json.dumps do transportu HTTP. Jeśli potrzebujesz pełnego kodowania w wire-format Protobuf, podłącz dataclasses do protobuf-python albo użyj ich jako typowanej warstwy przed klientem gRPC.
Kiedy faktycznie oszczędza czas
Szkicowanie typów dla nowego serwisu gRPC w Pythonie
Zaczynasz nowy serwis konsumujący istniejące API Protobuf. Chcesz czyste dataclasses dla kształtów request/response bez odpalania jeszcze protoc. Wklej schemat, wrzuć wynik do types.py, pisz logikę biznesową przeciwko dataclasses, podłącz gRPC Python później, kiedy będziesz gotowy.
Mockowanie danych Protobuf w pytest
Generowane klasy wiadomości Protobuf są upierdliwe do budowania w testach, bo każde pole ma własny setter, a konstruktory nie przyjmują wszystkich pól jako kwargs. Ręcznie zwijane dataclasses przyjmują — Order(order_id="ORD-42", customer_name="Ava Chen", total_amount=99.50) po prostu działa. Użyj tego wyniku jako fixture i mocków, a prawdziwe klasy Protobuf zostaw do serializacji wire-format.
Recenzowanie zmiany w API Protobuf
Kolega z backendu dodał pola do Order i nową wartość OrderStatus. Chcesz wiedzieć, co twój kod klienta w Pythonie musi obsłużyć, bez odpalania pełnego buildu. Wklej nowe .proto, zrób diff wyjścia dataclass z aktualnymi typami i zostaw skupiony komentarz w review.
Szybkie skrypty i jednorazowe zadania ETL
Piszesz pięćdziesięciolinijkowy skrypt do backfillowania danych z dumpa JSON, który podąża za schematem Protobuf. Stawianie protoc dla skryptu jednorazowego to przesada. Weź dataclasses stąd, sparsuj JSON do nich, odpal skrypt, wyrzuć. Brak kroku build, brak toolchain, brak wygenerowanych plików zalegających w repo.
Najczęstsze pytania
Czy mój schemat jest gdzieś wysyłany?
Nie. Parser i emiter Pythona działają w całości w twojej przeglądarce jako JavaScript. Otwórz DevTools i obserwuj zakładkę Network podczas wklejania — zero requestów. Przydatne, gdy schemat zawiera wewnętrzne nazwy typów, ścieżki paczek lub cokolwiek, czego wolałbyś nie wysyłać do zewnętrznego serwisu.
Czemu dataclasses zamiast oficjalnych klas wiadomości protobuf-python?
Klasy generowane przez protoc działają, ale są rozwlekłe, trudne do mockowania w testach i głośne w code review. Dataclasses dają ci typowane kwargs, porównywanie równości i czyste repr za darmo. Jeśli potrzebujesz kodowania wire-format, możesz mapować między dataclasses a oficjalnymi typami wiadomości w cienkiej warstwie adaptera — większość zespołów uważa ten podział za lepszy niż typowanie wszystkiego względem klas generowanych.
Czemu IntEnum, a nie enumy o wartościach str?
Enumy Protobuf są na poziomie wire wartościami int — każda wartość ma numer taga. IntEnum dokładnie to pokrywa: OrderStatus.ORDER_STATUS_PAID jest jednocześnie nazwanym członkiem i liczbą całkowitą 2, która czysto przechodzi tam i z powrotem przez JSON lub wire format. Jeśli wolisz StrEnum (Python 3.11+) do kodowania JSON, wystarczy find-replace na IntEnum w wyniku.
Czemu pola wiadomości to Optional[Msg], a nie po prostu Msg?
W proto3 pojedyncze pole wiadomości może być nieustawione (brak ma znaczenie, w odróżnieniu od skalarów, gdzie domyślną wartością jest zero). Domyślne None pasuje do tej semantyki i utrzymuje referencje cykliczne kompilowalne — jeśli Order osadza Address, a address osadza z powrotem, żadna z dataclass nie musi być zdefiniowana jako pierwsza. from __future__ import annotations na górze pliku sprawia, że forward refs rozwiązują się w runtime przez PEP 563.
Jak obsługiwane jest map<K, V>?
Renderowane jako dict[K, V] z field(default_factory=dict) jako wartością domyślną. Mapy Protobuf z kluczami nie-stringowymi (map<int32, string>) stają się dict[int, str]. JSON zna tylko klucze stringowe, więc gdy serializujesz dict do JSON, klucze int stają się stringami — to specyfika specyfikacji JSON proto3, nie konwertera.
Czy obsługuje oneof?
Każde pole oneof emitowane jest jako zwykłe pole dataclass. Wynik nie wymusza ograniczenia "dokładnie jedno" — do tego potrzebowałbyś typu Union lub struktury dyskryminowanej, co zależy od tego, jak twój runtime modeluje wykluczanie. Płaski układ jest czytelny i zgadza się z tym, co większość pythonowych baz kodu robi w praktyce. Jeśli potrzebujesz ostrzejszego typowania — popraw ręcznie.
Powiązane narzędzia
Jeśli pracujesz z Protobuf, JSON i Pythonem, te dobrze się ze sobą łączą: