mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-24 22:27:55 -05:00
#14723 Python: Pin grpcio-tools to keep protobuf 6 gencode loadable
grpcio-tools 1.82.0+ (including its 1.82.0 pre-releases) bundles a protoc that emits protobuf 7.35.x gencode, which no protobuf 6 runtime can load. Pin grpcio-tools below that (excluding pre-releases via the '.dev0' trick, since a plain '<1.82' bound already let a 1.82.0rc release slip through once) and add a CI check that verifies the generated *_pb2.py files stay within the protobuf floor declared in pyproject.toml. Only the load-bearing bounds are kept: protobuf's '>=6.33.5' floor (must match the emitted gencode) and grpcio-tools' '<1.82.0.dev0' ceiling. Non-load-bearing bounds (protobuf's '<8', grpcio-tools' '>=1.81') were dropped since they don't change dependency resolution or protect against anything the above doesn't already cover.
This commit is contained in:
1 parent
d92091cc91
commit
d0d472aaa2
3 files changed
+102
-2
No files matched your search
@@ -324,6 +324,13 @@ jobs:
|
||||
ls cmakebuild/${{ matrix.config.ri-unit-test-path }}
|
||||
cmakebuild/${{ matrix.config.ri-unit-test-path }}
|
||||
|
||||
- name: (Python) Verify protobuf gencode compatibility
|
||||
if: matrix.config.build-python-module
|
||||
shell: bash
|
||||
run: |
|
||||
cd GrpcInterface/Python
|
||||
${{ steps.python-path.outputs.PYTHON_EXECUTABLE }} check_gencode_compatibility.py
|
||||
|
||||
- name: (Python) Build Python module
|
||||
if: matrix.config.build-python-module
|
||||
shell: bash
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
"""Check that the generated protobuf code can be loaded by every supported runtime.
|
||||
|
||||
The protobuf runtime refuses to load gencode newer than itself, so the gencode
|
||||
version emitted by grpcio-tools must not exceed the lower bound declared for
|
||||
protobuf in pyproject.toml. Nothing ties those two together: a grpcio-tools
|
||||
upgrade can move the gencode a full major version without any edit here, and
|
||||
the resulting package still installs cleanly and only fails at import time.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
from packaging.requirements import Requirement
|
||||
from packaging.version import Version
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
GENERATED = HERE / "rips" / "generated"
|
||||
GENCODE_PATTERN = re.compile(r"^# Protobuf Python Version: (\S+)", re.MULTILINE)
|
||||
|
||||
|
||||
def declared_protobuf_floor() -> Version:
|
||||
"""Lowest protobuf runtime a user of this package can end up with."""
|
||||
with (HERE / "pyproject.toml").open("rb") as f:
|
||||
dependencies = tomllib.load(f)["project"]["dependencies"]
|
||||
|
||||
requirements = [Requirement(d) for d in dependencies]
|
||||
protobuf = next((r for r in requirements if r.name == "protobuf"), None)
|
||||
if protobuf is None:
|
||||
sys.exit("protobuf is not declared in [project].dependencies")
|
||||
|
||||
floors = [
|
||||
Version(s.version) for s in protobuf.specifier if s.operator in (">=", "==")
|
||||
]
|
||||
if not floors:
|
||||
sys.exit(
|
||||
f"protobuf dependency '{protobuf}' has no lower bound to check against"
|
||||
)
|
||||
|
||||
return max(floors)
|
||||
|
||||
|
||||
def gencode_versions() -> dict[str, Version]:
|
||||
versions = {}
|
||||
for path in sorted(GENERATED.glob("*_pb2.py")):
|
||||
match = GENCODE_PATTERN.search(path.read_text(encoding="utf-8"))
|
||||
if match is None:
|
||||
sys.exit(f"{path.name} has no gencode version header")
|
||||
versions[path.name] = Version(match.group(1))
|
||||
return versions
|
||||
|
||||
|
||||
def main() -> None:
|
||||
floor = declared_protobuf_floor()
|
||||
versions = gencode_versions()
|
||||
if not versions:
|
||||
sys.exit(f"no generated *_pb2.py files in {GENERATED}, nothing was verified")
|
||||
|
||||
too_new = {name: v for name, v in versions.items() if v > floor}
|
||||
if too_new:
|
||||
listing = "\n".join(f" {name}: gencode {v}" for name, v in too_new.items())
|
||||
sys.exit(
|
||||
f"Generated code is newer than the oldest supported protobuf runtime ({floor}).\n"
|
||||
f"{listing}\n"
|
||||
"Pin grpcio-tools to a release emitting older gencode, or raise the protobuf "
|
||||
"lower bound in pyproject.toml. Note that raising it drops support for runtimes "
|
||||
"below the new bound."
|
||||
)
|
||||
|
||||
print(
|
||||
f"{len(versions)} generated files, gencode {max(versions.values())}, runtime floor {floor}: OK"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -13,13 +13,29 @@ requires-python = ">=3.11"
|
||||
authors = [{name = "Ceetron Solutions", email = "info@ceetronsolutions.com"}]
|
||||
dependencies = [
|
||||
"grpcio",
|
||||
"protobuf",
|
||||
# Floor must match the gencode version emitted by the pinned grpcio-tools
|
||||
# below: the protobuf runtime refuses to load gencode newer than itself.
|
||||
# No upper bound: protobuf runtimes stay backward compatible with older
|
||||
# gencode, so nothing here caps how new a runtime a user can install.
|
||||
"protobuf>=6.33.5",
|
||||
"typing_extensions",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"grpcio-tools",
|
||||
# 1.82.x bundles a protoc that emits protobuf 7.35.x gencode, which no
|
||||
# protobuf 6 runtime can load - including its 1.82.0 pre-releases, which
|
||||
# is why the bound goes below ".dev0" rather than just "<1.82": a plain
|
||||
# "<1.82" bound already let a 1.82.0 release candidate slip through in
|
||||
# CI once (pre-release versions sort below their final release).
|
||||
# No lower bound: the resolver already prefers the newest version
|
||||
# satisfying the upper bound, so ">=1.81" wasn't changing what gets
|
||||
# installed, only guarding against a future resolver picking something
|
||||
# much older if 1.81.x ever became unavailable.
|
||||
# Generating 6.x gencode keeps rips importable on both 6.x and 7.x
|
||||
# runtimes, so it stays installable next to packages that cap protobuf
|
||||
# below 7 (ortools and friends).
|
||||
"grpcio-tools<1.82.0.dev0",
|
||||
"pytest",
|
||||
"mypy",
|
||||
"types-protobuf",
|
||||
|
||||
Reference in new issue
Block a user