1{ 2 lib, 3 stdenv, 4 fetchPypi, 5 buildPythonPackage, 6 isPyPy, 7 pythonOlder, 8 9 # build-system 10 certifi, 11 pkg-config, 12 pybind11, 13 meson-python, 14 setuptools-scm, 15 pytestCheckHook, 16 python, 17 matplotlib, 18 fetchurl, 19 20 # native libraries 21 ffmpeg-headless, 22 freetype, 23 # By default, almost all tests fail due to the fact we use our version of 24 # freetype. We still use this argument to define the overridden 25 # derivation `matplotlib.passthru.tests.withoutOutdatedFreetype` - which 26 # builds matplotlib with the freetype version they default to, with which all 27 # tests should pass. 28 doCheck ? false, 29 qhull, 30 31 # propagates 32 contourpy, 33 cycler, 34 fonttools, 35 kiwisolver, 36 numpy, 37 packaging, 38 pillow, 39 pyparsing, 40 python-dateutil, 41 42 # optional 43 importlib-resources, 44 45 # GTK3 46 enableGtk3 ? false, 47 cairo, 48 gobject-introspection, 49 gtk3, 50 pycairo, 51 pygobject3, 52 53 # Tk 54 # Darwin has its own "MacOSX" backend, PyPy has tkagg backend and does not support tkinter 55 enableTk ? (!stdenv.hostPlatform.isDarwin && !isPyPy), 56 tkinter, 57 58 # Qt 59 enableQt ? false, 60 pyqt5, 61 62 # Webagg 63 enableWebagg ? false, 64 tornado, 65 66 # nbagg 67 enableNbagg ? false, 68 ipykernel, 69 70 # required for headless detection 71 libX11, 72 wayland, 73 74 # Reverse dependency 75 sage, 76}: 77 78let 79 interactive = enableTk || enableGtk3 || enableQt; 80in 81 82buildPythonPackage rec { 83 version = "3.10.1"; 84 pname = "matplotlib"; 85 pyproject = true; 86 87 disabled = pythonOlder "3.10"; 88 89 src = fetchPypi { 90 inherit pname version; 91 hash = "sha256-6NLQ44gbEpJoWFv0dlrT7nOkWR13uaGMIUrH46efsro="; 92 }; 93 94 env.XDG_RUNTIME_DIR = "/tmp"; 95 96 # Matplotlib tries to find Tcl/Tk by opening a Tk window and asking the 97 # corresponding interpreter object for its library paths. This fails if 98 # `$DISPLAY` is not set. The fallback option assumes that Tcl/Tk are both 99 # installed under the same path which is not true in Nix. 100 # With the following patch we just hard-code these paths into the install 101 # script. 102 postPatch = 103 '' 104 substituteInPlace pyproject.toml \ 105 --replace-fail "meson-python>=0.13.1,<0.17.0" meson-python 106 107 patchShebangs tools 108 '' 109 + lib.optionalString (stdenv.hostPlatform.isLinux && interactive) '' 110 # fix paths to libraries in dlopen calls (headless detection) 111 substituteInPlace src/_c_internal_utils.cpp \ 112 --replace-fail libX11.so.6 ${libX11}/lib/libX11.so.6 \ 113 --replace-fail libwayland-client.so.0 ${wayland}/lib/libwayland-client.so.0 114 ''; 115 116 nativeBuildInputs = [ pkg-config ] ++ lib.optionals enableGtk3 [ gobject-introspection ]; 117 118 buildInputs = 119 [ 120 ffmpeg-headless 121 freetype 122 qhull 123 ] 124 ++ lib.optionals enableGtk3 [ 125 cairo 126 gtk3 127 ]; 128 129 # clang-11: error: argument unused during compilation: '-fno-strict-overflow' [-Werror,-Wunused-command-line-argument] 130 hardeningDisable = lib.optionals stdenv.hostPlatform.isDarwin [ "strictoverflow" ]; 131 132 build-system = [ 133 certifi 134 numpy 135 pybind11 136 meson-python 137 setuptools-scm 138 ]; 139 140 dependencies = 141 [ 142 # explicit 143 contourpy 144 cycler 145 fonttools 146 kiwisolver 147 numpy 148 packaging 149 pillow 150 pyparsing 151 python-dateutil 152 ] 153 ++ lib.optionals (pythonOlder "3.10") [ importlib-resources ] 154 ++ lib.optionals enableGtk3 [ 155 pycairo 156 pygobject3 157 ] 158 ++ lib.optionals enableQt [ pyqt5 ] 159 ++ lib.optionals enableWebagg [ tornado ] 160 ++ lib.optionals enableNbagg [ ipykernel ] 161 ++ lib.optionals enableTk [ tkinter ]; 162 163 mesonFlags = lib.mapAttrsToList lib.mesonBool { 164 system-freetype = true; 165 system-qhull = true; 166 # Otherwise GNU's `ar` binary fails to put symbols from libagg into the 167 # matplotlib shared objects. See: 168 # -https://github.com/matplotlib/matplotlib/issues/28260#issuecomment-2146243663 169 # -https://github.com/matplotlib/matplotlib/issues/28357#issuecomment-2155350739 170 b_lto = false; 171 }; 172 173 passthru.tests = { 174 inherit sage; 175 withOutdatedFreetype = matplotlib.override { 176 doCheck = true; 177 freetype = freetype.overrideAttrs (_: { 178 src = fetchurl { 179 url = "mirror://savannah/freetype/freetype-old/freetype-2.6.1.tar.gz"; 180 hash = "sha256-Cjx9+9ptoej84pIy6OltmHq6u79x68jHVlnkEyw2cBQ="; 181 }; 182 patches = [ ]; 183 }); 184 }; 185 }; 186 187 pythonImportsCheck = [ "matplotlib" ]; 188 inherit doCheck; 189 nativeCheckInputs = [ pytestCheckHook ]; 190 preCheck = '' 191 # https://matplotlib.org/devdocs/devel/testing.html#obtain-the-reference-images 192 find lib -name baseline_images -printf '%P\n' | while read p; do 193 cp -r lib/"$p" $out/${python.sitePackages}/"$p" 194 done 195 # Tests will fail without these files as well 196 cp \ 197 lib/matplotlib/tests/{mpltest.ttf,cmr10.pfb,Courier10PitchBT-Bold.pfb} \ 198 $out/${python.sitePackages}/matplotlib/tests/ 199 # https://github.com/NixOS/nixpkgs/issues/255262 200 cd $out 201 ''; 202 203 meta = with lib; { 204 description = "Python plotting library, making publication quality plots"; 205 homepage = "https://matplotlib.org/"; 206 changelog = "https://github.com/matplotlib/matplotlib/releases/tag/v${version}"; 207 license = with licenses; [ 208 psfl 209 bsd0 210 ]; 211 maintainers = with maintainers; [ 212 lovek323 213 veprbl 214 ]; 215 }; 216}