From 05ba85921147da77ee2ec12f1d833f5b3afb710d Mon Sep 17 00:00:00 2001 From: Thomas Ilsche Date: Wed, 1 Mar 2023 12:33:40 +0100 Subject: [PATCH] fix: protobuf version guessing, fixes #143 During the build process, protoc is invoked to build protobuf files. These built files are deployed to users, and thus the users require a compatible python-protobuf version. For that, the required protobuf version is set during the build process in setup.py. However, this version selection is not up to date with the versioning scheme used by protobuf. protobuf keeps the major version independent between languages, and minor/patch versions in sync. E.g., as of the time of writing, python-protobuf 4.21.12 is compatible with libprotoc 3.21.12. see: https://protobuf.dev/news/2022-05-06/ However, it is not clear under which circumstances these versions are compatible to each other. (I.e., even if minor/patch version are different, the binary format may still be compatible.) This makes correctly predicting the required (potentially unrealeased) python-protobuf version impossible. Co-authored-by: Hannes T <80697868+s9105947@users.noreply.github.com> --- setup.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 768419bd..321b3105 100755 --- a/setup.py +++ b/setup.py @@ -13,9 +13,11 @@ import re import subprocess import sys +from bisect import bisect_right from distutils.errors import DistutilsFileError from distutils.log import ERROR, INFO from distutils.spawn import find_executable +from operator import itemgetter from typing import Optional, Tuple import mypy_protobuf @@ -58,16 +60,39 @@ def protoc_version(protoc: str) -> Tuple[int, int, int]: return tuple(int(version_search.group(g)) for g in ("major", "minor", "patch")) -def make_protobuf_requirement(major: int, minor: int, patch: int) -> str: - """Sometimes the versions of libprotoc and the python package `protobuf` are out of sync. +# This encodes on which minor protobuf version the major python protobuf +# version was bumped +protobuf_version_mapping = ( + (3, 0), + (4, 21), +) + - For example, while there was protoc version 3.12.3, the latest release of - `protobuf` was 3.12.2. So we'll just depend on `x.y.0` and hope that - there's no breaking changes between patches. +def make_protobuf_requirement(major: int, minor: int, patch: int) -> str: + """ + We need to figure out a compatible version range of the python protobuf + package based on the version of the installed `protoc`. However, there is + no clean way to determine if those versions are compatible. + Between protobuf packages for different languages/libprotoc major versions + may diverge for the same release, while minor and patch versions align. + Different releases may or may not be compatible... + We can not predict which python protobuf versions will be compatible. + Hence, for compatibility this uses the following approach: + We hardcode a minor->major map, so the build works sort of like this + 1) get m(major).n(minor).p(patch) from protoc + 2) m' = 3 if n < 21 else 4 (as encoded in protobuf_version_mapping) + 2) depend on protobuf>=m'.n,={py_major}.{minor}, <{py_major}.{minor+1}" def get_protobuf_requirement() -> str: