mrkeyoor.com_
Sat 19 Sept 23:48 UTC
PyPIUtilsupdated 19 Sept 2026

protobuf review

protobuf 7.36.0 is the Python runtime that generated Protocol Buffer classes use to encode, decode, inspect, and convert typed messages. You define field numbers and types in a `.proto` file, run the separate `protoc` compiler, then import the resulting `_pb2.py` module. The bytes can be read by protobuf runtimes in other languages, provided every side follows the same schema evolution rules. Release 7.36.0 adds Python buffer assignment for repeated scalar fields, corrects out-of-range `pop()` errors, protects descriptor-pool caches with a mutex, and fixes upb memory bugs.

Verdict

protobuf 7.36.0 installed in 0.2 seconds and used 2 MB in our sandbox, with 0 direct dependencies and 0 audit findings, making the runtime cheap once a schema toolchain already exists. Install it for gRPC or a cross-language wire contract; use JSON or msgpack when compiler and compatibility work would outweigh that benefit.

We installed it

Lab card: what happened when we installed protobufScreenshot of protobuf documentation
Install✓ · 0.2s1 package on disk · 2 MB
Importimport google in 0.02s · compiled extensions · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does protobuf install cleanly?

Yes. In a fresh container with an empty cache, pip install protobuf finished in 0.2s, leaving 1 package and 2 MB on disk. pip-audit reported no known vulnerabilities.

What does protobuf need to run?

Python >=3.10, and a platform wheel with compiled extensions. In our run import google succeeded in 0.02s.

protobuf or flatbuffers: which should you use?

flatbuffers: Use it when reading serialized data without a separate decode step is worth a more specialized generated API. protobuf 7.36.0 installed in 0.2 seconds and used 2 MB in our sandbox, with 0 direct dependencies and 0 audit findings, making the runtime cheap once a schema toolchain already exists.

When should you not use protobuf?

Choose JSON with a validator for a small internal API when readable logs and no code-generation step matter more than a binary contract.

API stability3/5The binary format has strict compatibility rules around field numbers, unknown fields, and safe schema changes, so well-managed messages can outlive individual deployments. Python upgrades still need coordination because generated modules validate runtime compatibility. Version 7.36.0 also changes container error behavior and makes scalar options immutable under upb, which can expose code that depended on older runtime details.
Docs4/5The official protobuf.dev site documents the schema language, Python generation, field presence, JSON mapping, editions, migration rules, and version support. The repository README clearly separates the compiler from each language runtime. Python newcomers still have to connect several pages to answer one practical question: which compiler to install, where generated files belong, and how to produce useful type stubs.
Maintenance5/5GitHub showed a push on 2026-08-26, 71,831 stars, and 312 open issues and pull requests in an unarchived repository. The v36.0 release arrived on 2026-08-20. Its Python work includes a heap-use-after-free fix, a memory-leak fix, descriptor-cache locking, JSON depth enforcement, faster assignment, and corrected repeated-container errors, evidence of active work below the public API surface.
Ecosystem5/5The project publishes runtimes or linked implementations for C++, Java, Python, Objective-C, C#, Ruby, Go, PHP, Dart, and JavaScript, while gRPC builds its messages on the same format. The package records 213,129,802 weekly downloads. That reach makes protobuf a practical shared contract, though it also means one Python environment may inherit competing runtime constraints from Google clients, telemetry packages, and gRPC tooling.

Discussed on

  1. hnParsing Protobuf at 2+GB/S: How I Learned to Love Tail Calls in C586 points
  2. hnParsing protobuf at 2+GB/s: how I learned to love tail calls in C (2021)366 points
  3. hnFinding a $5,000 Google Maps XSS by fiddling with Protobuf304 points
  4. hnA new ProtoBuf generator for Go296 points
  5. hnGo Protobuf: The New Opaque API287 points

Use it if

  • A Python service shares a versioned message contract with clients or services written in other languages.
  • Your application uses gRPC, whose request and response objects are generated from protobuf schemas.
  • Old readers must accept newer messages and preserve fields they do not recognize while forwarding them.
  • Your team can pin the compiler, regenerate code in CI, and review field-number changes as part of API work.
Skip it if

Setup reality

Our Python 3.12 sandbox installed protobuf 7.36.0 in 0.2 seconds. The result was 1 package occupying 2 MB, with 0 direct dependencies and 0 known vulnerabilities from pip-audit. It requires Python 3.10 or newer and includes compiled .so extensions. The package has no py.typed marker. import google completed successfully in 0.02 seconds.

The install supplies the Python runtime only. Download a released protoc binary, or use a separate compiler package, and run it with stable include and output paths. A source such as billing/invoice.proto produces an _pb2.py module whose imports reflect the schema tree. Generate .pyi files with --pyi_out when your compiler supports that output, since this wheel itself does not advertise typing through py.typed.

Compiler output and runtime versions are coupled by a documented compatibility window. Upgrade them together and regenerate checked-in modules before deploying. A stale generated module can fail during import, long before a request reaches the parser. Schema changes carry their own permanent bookkeeping: never recycle a removed field number, reserve deleted names and numbers, and use optional when code must distinguish an absent scalar from its default value.

Generated messages have container rules that surprise Python users. Mutate nested messages or call CopyFrom() instead of assigning a new object. Use add() for repeated messages. Parsing into an existing instance merges fields, so clear it first or allocate a new message. Protobuf JSON also has its own names, integer encodings, and presence behavior; test JSON gateways separately from the binary path.

Patterns

Generate Python modules and stubs compile-schema

protoc -I schemas \
  --python_out=src \
  --pyi_out=src \
  schemas/acme/person.proto

The protobuf wheel does not contain `protoc`. Pin a released compiler in CI and keep its generated output inside the runtime compatibility window.

Create a generated message construct-message

from acme import person_pb2

person = person_pb2.Person(
    id=42,
    name="Ada",
    emails=["ada@example.com"],
)

Unset scalar fields read as schema defaults. Use `optional` in the schema when zero or an empty string must differ from absence.

Serialize and parse binary data serialize-message

payload = person.SerializeToString()

copy = person_pb2.Person()
copy.ParseFromString(payload)

`ParseFromString()` merges into its receiver. Allocate a new message or call `Clear()` before reusing an instance.

Set a nested message populate-nested-message

profile = person_pb2.Profile()
profile.address.city = "Delhi"

address = person_pb2.Address(city="Mumbai")
profile.address.CopyFrom(address)

Direct assignment to a message field raises an error. Mutate its fields or copy another message of the same generated type.

Add repeated message values append-repeated-message

member = team.members.add()
member.id = 7
member.name = "Lin"

team.labels.extend(["backend", "on-call"])

Repeated message containers use `add()`. Repeated scalar containers accept familiar operations such as `append()` and `extend()`.

Write and inspect a map use-map-field

job.tags["region"] = "ap-south-1"

for key, value in job.tags.items():
    print(key, value)

Reading a missing scalar map key can insert its default value. Test membership before lookup when mutation would be a bug.

Convert a message to protobuf JSON convert-json

from google.protobuf import json_format

text = json_format.MessageToJson(
    person,
    preserving_proto_field_name=True,
)
restored = json_format.Parse(text, person_pb2.Person())

The JSON mapping is defined by protobuf and differs from a plain object dump. Unknown JSON fields raise unless parsing enables `ignore_unknown_fields`.

Distinguish zero from absent check-field-presence

# schema: optional int32 retries = 1;
request = jobs_pb2.Request()
assert not request.HasField("retries")

request.retries = 0
assert request.HasField("retries")

`HasField()` works for message fields and presence-enabled scalars. A plain proto3 scalar has no explicit presence.

Find the active oneof member inspect-oneof

payment.card.token = "tok_123"
assert payment.WhichOneof("method") == "card"

payment.bank_account = "DE89..."
assert payment.WhichOneof("method") == "bank_account"

Setting one member clears the previous member in that `oneof`. `WhichOneof()` returns `None` when none is present.

Convert an aware datetime handle-timestamp

from datetime import datetime, timezone
from google.protobuf.timestamp_pb2 import Timestamp

ts = Timestamp()
ts.FromDatetime(datetime.now(timezone.utc))
value = ts.ToDatetime(tzinfo=timezone.utc)

Passing `tzinfo` to `ToDatetime()` returns an aware datetime. Without it, the result represents UTC in a naive object.

Print a message for debugging format-text

from google.protobuf import text_format

print(text_format.MessageToString(person))

parsed = person_pb2.Person()
text_format.Parse('id: 42 name: "Ada"', parsed)

Text format needs the schema and is intended for protobuf-aware tools. Do not treat it as a stable replacement for the binary encoding.

Apply a partial update merge-messages

current = person_pb2.Person(id=42, name="Old")
patch = person_pb2.Person(name="New")
current.MergeFrom(patch)

`MergeFrom()` combines fields according to protobuf merge rules. Presence controls whether a scalar in the patch can intentionally overwrite a value with its default.

Alternatives

PackageRegistryPick it when
flatbuffersPyPIUse it when reading serialized data without a separate decode step is worth a more specialized generated API.
msgpackPyPIUse it for compact binary dictionaries and lists when you do not want schemas or code generation.
marshmallowPyPIUse it for Python object validation and serialization when other languages do not share the contract.

More utils guides

lru-cache · type-fest · ajv · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.