1{ buildPackages
2, buildPythonPackage
3, fetchpatch
4, isPyPy
5, lib
6, numpy
7, protobuf
8, pytestCheckHook
9, pythonAtLeast
10, substituteAll
11, tzdata
12}:
13
14assert lib.versionOlder protobuf.version "21" -> throw "Protobuf 21 or newer required";
15
16let
17 protobufVersionMajor = lib.versions.major protobuf.version;
18 protobufVersionMinor = lib.versions.minor protobuf.version;
19in
20buildPythonPackage {
21 inherit (protobuf) pname src;
22
23 # protobuf 21 corresponds with its python library 4.21
24 version = "4.${protobufVersionMajor}.${protobufVersionMinor}";
25
26 sourceRoot = "${protobuf.src.name}/python";
27
28 patches = lib.optionals (lib.versionAtLeast protobuf.version "22") [
29 # Replace the vendored abseil-cpp with nixpkgs'
30 (substituteAll {
31 src = ./use-nixpkgs-abseil-cpp.patch;
32 abseil_cpp_include_path = "${lib.getDev protobuf.abseil-cpp}/include";
33 })
34 ]
35 ++ lib.optionals (pythonAtLeast "3.11" && lib.versionOlder protobuf.version "22") [
36 (fetchpatch {
37 name = "support-python311.patch";
38 url = "https://github.com/protocolbuffers/protobuf/commit/2206b63c4649cf2e8a06b66c9191c8ef862ca519.diff";
39 stripLen = 1; # because sourceRoot above
40 hash = "sha256-3GaoEyZIhS3QONq8LEvJCH5TdO9PKnOgcQF0GlEiwFo=";
41 })
42 ];
43
44 prePatch = ''
45 if [[ "$(<../version.json)" != *'"python": "'"$version"'"'* ]]; then
46 echo "Python library version mismatch. Derivation version: $version, actual: $(<../version.json)"
47 exit 1
48 fi
49 '';
50
51 # Remove the line in setup.py that forces compiling with C++14. Upstream's
52 # CMake build has been updated to support compiling with other versions of
53 # C++, but the Python build has not. Without this, we observe compile-time
54 # errors using GCC.
55 #
56 # Fedora appears to do the same, per this comment:
57 #
58 # https://github.com/protocolbuffers/protobuf/issues/12104#issuecomment-1542543967
59 #
60 postPatch = ''
61 sed -i "/extra_compile_args.append('-std=c++14')/d" setup.py
62 '';
63
64 nativeBuildInputs = lib.optional isPyPy tzdata;
65
66 buildInputs = [ protobuf ];
67
68 propagatedNativeBuildInputs = [
69 # For protoc of the same version.
70 buildPackages."protobuf_${protobufVersionMajor}"
71 ];
72
73 setupPyGlobalFlags = [ "--cpp_implementation" ];
74
75 nativeCheckInputs = [
76 pytestCheckHook
77 ] ++ lib.optionals (lib.versionAtLeast protobuf.version "22") [
78 numpy
79 ];
80
81 disabledTests = lib.optionals isPyPy [
82 # error message differs
83 "testInvalidTimestamp"
84 # requires tracemalloc which pypy does not implement
85 # https://foss.heptapod.net/pypy/pypy/-/issues/3048
86 "testUnknownFieldsNoMemoryLeak"
87 # assertion is not raised for some reason
88 "testStrictUtf8Check"
89 ];
90
91 disabledTestPaths = lib.optionals (lib.versionAtLeast protobuf.version "23") [
92 # The following commit (I think) added some internal test logic for Google
93 # that broke generator_test.py. There is a new proto file that setup.py is
94 # not generating into a .py file. However, adding this breaks a bunch of
95 # conflict detection in descriptor_test.py that I don't understand. So let's
96 # just disable generator_test.py for now.
97 #
98 # https://github.com/protocolbuffers/protobuf/commit/5abab0f47e81ac085f0b2d17ec3b3a3b252a11f1
99 #
100 "google/protobuf/internal/generator_test.py"
101 ];
102
103 pythonImportsCheck = [
104 "google.protobuf"
105 "google.protobuf.internal._api_implementation" # Verify that --cpp_implementation worked
106 ];
107
108 passthru = {
109 inherit protobuf;
110 };
111
112 meta = with lib; {
113 description = "Protocol Buffers are Google's data interchange format";
114 homepage = "https://developers.google.com/protocol-buffers/";
115 license = licenses.bsd3;
116 maintainers = with maintainers; [ knedlsepp ];
117 };
118}