Beispiel
protobuf 6.33.6: Know which protobuf backend actually loaded: upb ships inside the binary wheel, so a musl/Alpine image with no prebuilt wheel silently gets the pure-Python fallback with different descriptor types and no warning
Verifiziertes Beispiel für pypi protobuf 6.33.6: Know which protobuf backend actually loaded: upb ships inside the binary wheel, so a musl/Alpine image with…
sha256:d7bea0b572b3364fc334f71559dbe438cfebc689607a583f66c1d6e1e9e2cc91
Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen.
Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen.
MIT-0
Ausführungsbelege
Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.
- Beleggrundlage
- Signierter Vertrag bestanden
- Verifizierungsbelege
- 3
- Signaturschlüssel, die es gebaut haben
- 3
Deklarierte Umgebung
python linux x64 python python pip
Umgebungen der Verifizierungsläufe
| Umgebung | Contract | Stufen | Lauf |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-15 |
| python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-18 |
| python 3.12 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1python:3.12-slim@sha256:09f7da3bc104… |
2026-09-08 |
Fall
HOW- Ziel
- Know which protobuf backend actually loaded: upb ships inside the binary wheel, so a musl/Alpine image with no prebuilt wheel silently gets the pure-Python fallback with different descriptor types and no warning
- Pakete
- Symbole
-
- google.protobuf.internal.api_implementation.Type
- google.protobuf.descriptor.Descriptor
- Umgebung
- python
- Erstellt
- 2026-08-15T11:26:57Z
Contract
- assert the default backend is whatever the platform's wheel provided: upb when the C extension is importable, python when it is not, with no warning either way
- assert the pure-Python fallback carries different descriptor classes (google.protobuf.descriptor rather than google._upb._message), so isinstance and __module__ checks written against upb stop matching
- assert PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python forces the pure-Python backend
- assert PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp keeps Type()=='cpp' with no _c_module and then fails loudly on import, rather than falling back
- assert an unsupported backend name raises ValueError naming the supported ones
- assert backend selection is cached at first import, so mutating the environment afterwards changes nothing
Dateien
- NOTES.md
- csx.json
- requirements.lock
- requirements.txt
- test/contract.py
Quelltext
A model would set `PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION="cpp"` expecting fast C++ acceleration (legacy behavior from protobuf <= 3.x) or a graceful fallback to pure Python if C++ extensions are unavailable.
Instead, requesting `"cpp"` on modern protobuf wheels emits a `UserWarning: Selected implementation cpp is not available.` but leaves `api_implementation.Type() == "cpp"` with `_c_module = None` (unlike `"upb"` which actively falls back to `"python"` on missing extension). When `google.protobuf.descriptor` or any generated proto class is imported, it unconditionally tries `from google.protobuf.pyext import _message` and fails loudly with `ImportError: cannot import name '_message' from 'google.protobuf.pyext'`.
{"case":{"caseId":"case:sha256:6483191fa9a850cace107ffc29c4bf0f6e9b4efc052f5db1ffeb3a045c8bf212","constraints":{"runtime":"python"},"contract":["assert the default backend is whatever the platform's wheel provided: upb when the C extension is importable, python when it is not, with no warning either way","assert the pure-Python fallback carries different descriptor classes (google.protobuf.descriptor rather than google._upb._message), so isinstance and __module__ checks written against upb stop matching","assert PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python forces the pure-Python backend","assert PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp keeps Type()=='cpp' with no _c_module and then fails loudly on import, rather than falling back","assert an unsupported backend name raises ValueError naming the supported ones","assert backend selection is cached at first import, so mutating the environment afterwards changes nothing"],"goal":"Know which protobuf backend actually loaded: upb ships inside the binary wheel, so a musl/Alpine image with no prebuilt wheel silently gets the pure-Python fallback with different descriptor types and no warning","kind":"HOW","packages":["pkg:pypi/protobuf@6.33.6"],"schemaVersion":1,"symbols":["google.protobuf.internal.api_implementation.Type","google.protobuf.descriptor.Descriptor"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/protobuf@6.33.6"],"schemaVersion":1,"symbols":["google.protobuf.internal.api_implementation.Type","google.protobuf.descriptor.Descriptor"],"verifierAdapter":"python@1"}
protobuf==6.33.6
protobuf==6.33.6
import os
import sys
import warnings
def reset_proto_env(backend=None):
"""Reset environment and clear all protobuf modules from sys.modules."""
if backend is None:
os.environ.pop("PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION", None)
else:
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = backend
to_delete = [
k
for k in sys.modules
if k.startswith("google.protobuf")
or k.startswith("google._upb")
or k.startswith("google3")
]
for k in to_delete:
del sys.modules[k]
def test_default_backend_follows_the_wheel_the_platform_got():
# Naive expectation: "modern protobuf defaults to the upb C extension",
# which is what every answer about this says.
#
# Reality: that is a statement about the WHEEL, not about protobuf. upb
# ships inside the binary wheel. On a platform with no prebuilt wheel --
# musl/Alpine being the one people actually hit, since the manylinux
# wheels are glibc -- pip installs the pure-Python fallback and
# api_implementation.Type() is "python". Nothing warns. The code runs,
# 10-50x slower, and the descriptor types are different classes, so
# anything that compares __module__ or isinstance against the upb types
# silently stops matching.
#
# This is a one-line-of-Dockerfile difference: python:3.13-alpine versus
# python:3.13-slim decides it.
reset_proto_env(None)
from google.protobuf.internal import api_implementation
from google.protobuf import descriptor_pb2
from google.protobuf.descriptor import Descriptor
impl = api_implementation.Type()
assert impl in ("upb", "python"), impl
descriptor_module = type(descriptor_pb2.FileDescriptorProto.DESCRIPTOR).__module__
if impl == "upb":
assert api_implementation._c_module is not None
assert api_implementation._c_module.__name__ == "google._upb._message"
assert descriptor_module == "google._upb._message"
else:
# The fallback is not an error state and says nothing about itself.
assert api_implementation._c_module is None
assert descriptor_module == "google.protobuf.descriptor"
try:
import google._upb._message # noqa: F401
raise AssertionError(
"the pure-Python backend was selected while the upb extension is importable"
)
except ImportError:
pass
assert isinstance(descriptor_pb2.FileDescriptorProto.DESCRIPTOR, Descriptor)
print("default backend on this platform:", impl)
def test_explicit_python_backend():
# Setting PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python forces pure Python implementation.
reset_proto_env("python")
from google.protobuf.internal import api_implementation
from google.protobuf import descriptor_pb2
from google.protobuf.descriptor import Descriptor
assert api_implementation.Type() == "python"
assert api_implementation._c_module is None
assert type(descriptor_pb2.FileDescriptorProto.DESCRIPTOR).__module__ == "google.protobuf.descriptor"
assert isinstance(descriptor_pb2.FileDescriptorProto.DESCRIPTOR, Descriptor)
def test_cpp_backend_missing_in_wheel_raises_import_error():
# Naive expectation: setting 'cpp' enables C++ extension or falls back gracefully to Python.
# Reality: api_implementation warns but keeps Type() == 'cpp' and _c_module is None.
# Subsequent import of google.protobuf.descriptor attempts `from google.protobuf.pyext import _message`
# and raises ImportError loudly (no fallback occurs).
reset_proto_env("cpp")
with warnings.catch_warnings(record=True) as caught_warnings:
warnings.simplefilter("always")
from google.protobuf.internal import api_implementation
assert api_implementation.Type() == "cpp"
assert api_implementation._c_module is None
assert any(
"Selected implementation cpp is not available" in str(w.message)
for w in caught_warnings
)
try:
from google.protobuf import descriptor
raise AssertionError("Expected ImportError because cpp pyext._message is not in prebuilt wheels")
except ImportError as err:
assert "_message" in str(err)
def test_invalid_backend_name_raises_value_error():
# Naive expectation: unknown backend strings default to python or are ignored.
# Reality: api_implementation immediately raises ValueError listing supported backends.
reset_proto_env("invalid_backend")
try:
from google.protobuf.internal import api_implementation
raise AssertionError("Expected ValueError for unsupported backend")
except ValueError as err:
assert "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION" in str(err)
assert "python" in str(err) and "cpp" in str(err) and "upb" in str(err)
def test_runtime_env_mutation_after_import_is_cached():
# Backend selection is performed once during initial module load and cached.
# Mutating os.environ later in the process has no effect.
reset_proto_env("python")
from google.protobuf.internal import api_implementation
assert api_implementation.Type() == "python"
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "upb"
assert api_implementation.Type() == "python"
if __name__ == "__main__":
test_default_backend_follows_the_wheel_the_platform_got()
test_explicit_python_backend()
test_cpp_backend_missing_in_wheel_raises_import_error()
test_invalid_backend_name_raises_value_error()
test_runtime_env_mutation_after_import_is_cached()
print("Contract assertions passed.")