summaryrefslogtreecommitdiff
path: root/pkgs/development/python-modules/protobuf/4.nix
blob: 29879ae3c9d851ecd5e69f5c1254621eb5e4ce3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{
  buildPackages,
  buildPythonPackage,
  fetchpatch,
  isPyPy,
  lib,
  stdenv,
  numpy,
  protobuf,
  pytestCheckHook,
  pythonAtLeast,
  replaceVars,
  tzdata,
}:

assert lib.versionOlder protobuf.version "21" -> throw "Protobuf 21 or newer required";

let
  protobufVersionMajor = lib.versions.major protobuf.version;
  protobufVersionMinor = lib.versions.minor protobuf.version;
in
buildPythonPackage {
  inherit (protobuf) pname src;

  # protobuf 21 corresponds with its python library 4.21
  version = "4.${protobufVersionMajor}.${protobufVersionMinor}";
  format = "setuptools";

  sourceRoot = "${protobuf.src.name}/python";

  patches =
    lib.optionals (lib.versionAtLeast protobuf.version "22") [
      # Replace the vendored abseil-cpp with nixpkgs'
      (replaceVars ./use-nixpkgs-abseil-cpp.patch {
        abseil_cpp_include_path = "${lib.getDev protobuf.abseil-cpp}/include";
      })
    ]
    ++ lib.optionals (pythonAtLeast "3.11" && lib.versionOlder protobuf.version "22") [
      (fetchpatch {
        name = "support-python311.patch";
        url = "https://github.com/protocolbuffers/protobuf/commit/2206b63c4649cf2e8a06b66c9191c8ef862ca519.diff";
        stripLen = 1; # because sourceRoot above
        hash = "sha256-3GaoEyZIhS3QONq8LEvJCH5TdO9PKnOgcQF0GlEiwFo=";
      })
    ];

  prePatch = ''
    if [[ "$(<../version.json)" != *'"python": "'"$version"'"'* ]]; then
      echo "Python library version mismatch. Derivation version: $version, actual: $(<../version.json)"
      exit 1
    fi
  '';

  # Remove the line in setup.py that forces compiling with C++14. Upstream's
  # CMake build has been updated to support compiling with other versions of
  # C++, but the Python build has not. Without this, we observe compile-time
  # errors using GCC.
  #
  # Fedora appears to do the same, per this comment:
  #
  #   https://github.com/protocolbuffers/protobuf/issues/12104#issuecomment-1542543967
  #
  postPatch = ''
    sed -i "/extra_compile_args.append('-std=c++14')/d" setup.py

    # The former function has been renamed into the latter in Python 3.12.
    # Does not apply to all protobuf versions, hence --replace-warn.
    substituteInPlace google/protobuf/internal/json_format_test.py \
      --replace-warn assertRaisesRegexp assertRaisesRegex
  '';

  nativeBuildInputs = lib.optional isPyPy tzdata;

  buildInputs = [ protobuf ];

  propagatedNativeBuildInputs = [
    # For protoc of the same version.
    buildPackages."protobuf_${protobufVersionMajor}"
  ];

  setupPyGlobalFlags = [ "--cpp_implementation" ];

  nativeCheckInputs = [
    pytestCheckHook
  ]
  ++ lib.optionals (lib.versionAtLeast protobuf.version "22") [ numpy ];

  disabledTests =
    lib.optionals isPyPy [
      # error message differs
      "testInvalidTimestamp"
      # requires tracemalloc which pypy does not implement
      # https://foss.heptapod.net/pypy/pypy/-/issues/3048
      "testUnknownFieldsNoMemoryLeak"
      # assertion is not raised for some reason
      "testStrictUtf8Check"
    ]
    ++ lib.optionals stdenv.hostPlatform.is32bit [
      # OverflowError: timestamp out of range for platform time_t
      "testTimezoneAwareDatetimeConversionWhereTimestampLosesPrecision"
      "testTimezoneNaiveDatetimeConversionWhereTimestampLosesPrecision"
    ];

  disabledTestPaths =
    lib.optionals (lib.versionAtLeast protobuf.version "23") [
      # The following commit (I think) added some internal test logic for Google
      # that broke generator_test.py. There is a new proto file that setup.py is
      # not generating into a .py file. However, adding this breaks a bunch of
      # conflict detection in descriptor_test.py that I don't understand. So let's
      # just disable generator_test.py for now.
      #
      #   https://github.com/protocolbuffers/protobuf/commit/5abab0f47e81ac085f0b2d17ec3b3a3b252a11f1
      #
      "google/protobuf/internal/generator_test.py"
    ]
    ++ lib.optionals (lib.versionAtLeast protobuf.version "25") [
      "minimal_test.py" # ModuleNotFoundError: No module named 'google3'
    ];

  pythonImportsCheck = [
    "google.protobuf"
    "google.protobuf.internal._api_implementation" # Verify that --cpp_implementation worked
  ];

  passthru = {
    inherit protobuf;
  };

  meta = {
    description = "Protocol Buffers are Google's data interchange format";
    homepage = "https://developers.google.com/protocol-buffers/";
    license = lib.licenses.bsd3;
    maintainers = [ ];
    broken = lib.versionAtLeast protobuf.version "26";
  };
}