lol

pythonPackages.thumbor: 6.6.0 -> 6.7.0

This patch ensures that the currently broken `thumbor`[1] package builds
and works again.

The following problems were fixed:

* Rather than placing required packages (like `gifsicle` or `exiftool`)
into the build input list, we reference them explicitly where needed
to ensure that the package works after the build without further
installs.

* Skip the `test_redeye_applied` test case which is broken for a while
now.

[1] https://hydra.nixos.org/build/90290998

authored by

Maximilian Bosch and committed by
Robert Schütz
8dac8644 16c2c6b6

+293 -9
+277
pkgs/development/python-modules/thumbor/0001-Don-t-use-which-implementation-to-find-required-exec.patch
··· 1 + From bd5a5b58b438ff34d27781e28cd7fab93bfc9f3f Mon Sep 17 00:00:00 2001 2 + From: Maximilian Bosch <maximilian@mbosch.me> 3 + Date: Sat, 9 Mar 2019 23:26:30 +0100 4 + Subject: [PATCH] Don't use `which` implementation to find required executables 5 + 6 + Nix specific patch. 7 + 8 + Rather than relying on a global state, we set an absolute store path for 9 + all external dependencies to ensure their functionality. 10 + --- 11 + integration_tests/__init__.py | 4 ++-- 12 + tests/engines/test_gif.py | 2 +- 13 + tests/handlers/test_base_handler.py | 30 ++++++++++++++--------------- 14 + tests/optimizers/test_gifv.py | 2 +- 15 + tests/test_server.py | 4 ++++ 16 + tests/test_utils.py | 3 +++ 17 + thumbor/server.py | 7 +------ 18 + 7 files changed, 26 insertions(+), 26 deletions(-) 19 + 20 + diff --git a/integration_tests/__init__.py b/integration_tests/__init__.py 21 + index 9bdd0a3..7d9de8f 100644 22 + --- a/integration_tests/__init__.py 23 + +++ b/integration_tests/__init__.py 24 + @@ -15,7 +15,7 @@ class EngineCase(AsyncHTTPTestCase): 25 + def get_app(self): 26 + cfg = Config(SECURITY_KEY='ACME-SEC') 27 + server_params = ServerParameters(None, None, None, None, None, None) 28 + - server_params.gifsicle_path = which('gifsicle') 29 + + server_params.gifsicle_path = '@gifsicle@' 30 + 31 + cfg.DETECTORS = [ 32 + 'thumbor.detectors.face_detector', 33 + @@ -28,7 +28,7 @@ class EngineCase(AsyncHTTPTestCase): 34 + cfg.FILE_LOADER_ROOT_PATH = os.path.join(os.path.dirname(__file__), 'imgs') 35 + cfg.ENGINE = getattr(self, 'engine', None) 36 + cfg.USE_GIFSICLE_ENGINE = True 37 + - cfg.FFMPEG_PATH = which('ffmpeg') 38 + + cfg.FFMPEG_PATH = '@ffmpeg@' 39 + cfg.ENGINE_THREADPOOL_SIZE = 10 40 + cfg.OPTIMIZERS = [ 41 + 'thumbor.optimizers.gifv', 42 + diff --git a/tests/engines/test_gif.py b/tests/engines/test_gif.py 43 + index c0c8430..ce0cc51 100644 44 + --- a/tests/engines/test_gif.py 45 + +++ b/tests/engines/test_gif.py 46 + @@ -44,7 +44,7 @@ class GitEngineTestCase(TestCase): 47 + def get_server(self): 48 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 49 + server.security_key = 'ACME-SEC' 50 + - server.gifsicle_path = which('gifsicle') 51 + + server.gifsicle_path = '@gifsicle@' 52 + return server 53 + 54 + def get_context(self, *args, **kwargs): 55 + diff --git a/tests/handlers/test_base_handler.py b/tests/handlers/test_base_handler.py 56 + index 69dc110..4493abe 100644 57 + --- a/tests/handlers/test_base_handler.py 58 + +++ b/tests/handlers/test_base_handler.py 59 + @@ -557,7 +557,7 @@ class ImageOperationsWithAutoWebPTestCase(BaseImagingTestCase): 60 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 61 + server.security_key = 'ACME-SEC' 62 + ctx = Context(server, cfg, importer) 63 + - ctx.server.gifsicle_path = which('gifsicle') 64 + + ctx.server.gifsicle_path = '@gifsicle@' 65 + return ctx 66 + 67 + def get_as_webp(self, url): 68 + @@ -657,7 +657,7 @@ class ImageOperationsWithAutoWebPWithResultStorageTestCase(BaseImagingTestCase): 69 + server.security_key = 'ACME-SEC' 70 + ctx = Context(server, cfg, importer) 71 + ctx.request = self.get_request() 72 + - ctx.server.gifsicle_path = which('gifsicle') 73 + + ctx.server.gifsicle_path = '@gifsicle@' 74 + return ctx 75 + 76 + @property 77 + @@ -783,7 +783,7 @@ class ImageOperationsWithGifVTestCase(BaseImagingTestCase): 78 + cfg = Config(SECURITY_KEY='ACME-SEC') 79 + cfg.LOADER = "thumbor.loaders.file_loader" 80 + cfg.FILE_LOADER_ROOT_PATH = self.loader_path 81 + - cfg.FFMPEG_PATH = which('ffmpeg') 82 + + cfg.FFMPEG_PATH = '@ffmpeg@' 83 + cfg.OPTIMIZERS = [ 84 + 'thumbor.optimizers.gifv', 85 + ] 86 + @@ -793,7 +793,7 @@ class ImageOperationsWithGifVTestCase(BaseImagingTestCase): 87 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 88 + server.security_key = 'ACME-SEC' 89 + ctx = Context(server, cfg, importer) 90 + - ctx.server.gifsicle_path = which('gifsicle') 91 + + ctx.server.gifsicle_path = '@gifsicle@' 92 + return ctx 93 + 94 + def test_should_convert_animated_gif_to_mp4_when_filter_without_params(self): 95 + @@ -828,7 +828,7 @@ class ImageOperationsImageCoverTestCase(BaseImagingTestCase): 96 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 97 + server.security_key = 'ACME-SEC' 98 + ctx = Context(server, cfg, importer) 99 + - ctx.server.gifsicle_path = which('gifsicle') 100 + + ctx.server.gifsicle_path = '@gifsicle@' 101 + return ctx 102 + 103 + def test_can_get_image_cover(self): 104 + @@ -849,7 +849,7 @@ class ImageOperationsWithResultStorageTestCase(BaseImagingTestCase): 105 + cfg.RESULT_STORAGE_FILE_STORAGE_ROOT_PATH = self.root_path 106 + 107 + cfg.USE_GIFSICLE_ENGINE = True 108 + - cfg.FFMPEG_PATH = which('ffmpeg') 109 + + cfg.FFMPEG_PATH = '@ffmpeg@' 110 + cfg.AUTO_WEBP = True 111 + cfg.OPTIMIZERS = [ 112 + 'thumbor.optimizers.gifv', 113 + @@ -860,7 +860,7 @@ class ImageOperationsWithResultStorageTestCase(BaseImagingTestCase): 114 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 115 + server.security_key = 'ACME-SEC' 116 + ctx = Context(server, cfg, importer) 117 + - ctx.server.gifsicle_path = which('gifsicle') 118 + + ctx.server.gifsicle_path = '@gifsicle@' 119 + 120 + return ctx 121 + 122 + @@ -891,7 +891,7 @@ class ImageOperationsResultStorageOnlyTestCase(BaseImagingTestCase): 123 + cfg.RESULT_STORAGE = 'thumbor.result_storages.file_storage' 124 + cfg.RESULT_STORAGE_EXPIRATION_SECONDS = 60 125 + cfg.RESULT_STORAGE_FILE_STORAGE_ROOT_PATH = self.root_path 126 + - cfg.FFMPEG_PATH = which('ffmpeg') 127 + + cfg.FFMPEG_PATH = '@ffmpeg@' 128 + 129 + cfg.USE_GIFSICLE_ENGINE = True 130 + cfg.AUTO_WEBP = True 131 + @@ -904,7 +904,7 @@ class ImageOperationsResultStorageOnlyTestCase(BaseImagingTestCase): 132 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 133 + server.security_key = 'ACME-SEC' 134 + ctx = Context(server, cfg, importer) 135 + - ctx.server.gifsicle_path = which('gifsicle') 136 + + ctx.server.gifsicle_path = '@gifsicle@' 137 + 138 + return ctx 139 + 140 + @@ -1040,7 +1040,7 @@ class ImageOperationsWithMaxPixels(BaseImagingTestCase): 141 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 142 + server.security_key = 'ACME-SEC' 143 + ctx = Context(server, cfg, importer) 144 + - ctx.server.gifsicle_path = which('gifsicle') 145 + + ctx.server.gifsicle_path = '@gifsicle@' 146 + return ctx 147 + 148 + def test_should_error(self): 149 + @@ -1061,7 +1061,7 @@ class ImageOperationsWithRespectOrientation(BaseImagingTestCase): 150 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 151 + server.security_key = 'ACME-SEC' 152 + self.context = Context(server, cfg, importer) 153 + - self.context.server.gifsicle_path = which('gifsicle') 154 + + self.context.server.gifsicle_path = '@gifsicle@' 155 + return self.context 156 + 157 + def test_should_be_ok_when_orientation_exif(self): 158 + @@ -1153,7 +1153,7 @@ class ImageOperationsWithJpegtranTestCase(BaseImagingTestCase): 159 + cfg = Config(SECURITY_KEY='ACME-SEC') 160 + cfg.LOADER = "thumbor.loaders.file_loader" 161 + cfg.FILE_LOADER_ROOT_PATH = self.loader_path 162 + - cfg.JPEGTRAN_PATH = which('jpegtran') 163 + + cfg.JPEGTRAN_PATH = '@jpegtran@' 164 + cfg.PROGRESSIVE_JPEG = True, 165 + cfg.RESULT_STORAGE_STORES_UNSAFE = True, 166 + cfg.OPTIMIZERS = [ 167 + @@ -1175,9 +1175,7 @@ class ImageOperationsWithJpegtranTestCase(BaseImagingTestCase): 168 + f.write(response.body) 169 + f.close() 170 + 171 + - exiftool = which('exiftool') 172 + - if not exiftool: 173 + - raise AssertionError('exiftool was not found. Please install it to run thumbor\'s tests.') 174 + + exiftool = '@exiftool@' 175 + 176 + command = [ 177 + exiftool, 178 + @@ -1221,7 +1219,7 @@ class ImageOperationsWithoutStorage(BaseImagingTestCase): 179 + server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) 180 + server.security_key = 'ACME-SEC' 181 + ctx = Context(server, cfg, importer) 182 + - ctx.server.gifsicle_path = which('gifsicle') 183 + + ctx.server.gifsicle_path = '@gifsicle@' 184 + return ctx 185 + 186 + def test_meta(self): 187 + diff --git a/tests/optimizers/test_gifv.py b/tests/optimizers/test_gifv.py 188 + index 229e9cd..066f2d5 100644 189 + --- a/tests/optimizers/test_gifv.py 190 + +++ b/tests/optimizers/test_gifv.py 191 + @@ -31,7 +31,7 @@ class GifvOptimizerTest(TestCase): 192 + def get_context(self): 193 + conf = Config() 194 + conf.STATSD_HOST = '' 195 + - conf.FFMPEG_PATH = which('ffmpeg') 196 + + conf.FFMPEG_PATH = '@ffmpeg@' 197 + ctx = Context(config=conf) 198 + ctx.request = RequestParameters() 199 + ctx.request.filters.append('gifv') 200 + diff --git a/tests/test_server.py b/tests/test_server.py 201 + index 5b31750..c2a65dc 100644 202 + --- a/tests/test_server.py 203 + +++ b/tests/test_server.py 204 + @@ -11,6 +11,8 @@ 205 + from unittest import TestCase 206 + import mock 207 + 208 + +from nose.tools import nottest 209 + + 210 + from preggy import expect 211 + 212 + from thumbor.app import ThumborServiceApp 213 + @@ -118,6 +120,7 @@ class ServerTestCase(TestCase): 214 + expect(server_parameters.security_key).to_equal('something') 215 + 216 + @mock.patch.object(thumbor.server, 'which') 217 + + @nottest 218 + def test_validate_gifsicle_path(self, which_mock): 219 + server_parameters = mock.Mock(security_key=None) 220 + conf = Config(SECURITY_KEY='test', USE_GIFSICLE_ENGINE=True) 221 + @@ -128,6 +131,7 @@ class ServerTestCase(TestCase): 222 + expect(server_parameters.gifsicle_path).to_equal('/usr/bin/gifsicle') 223 + 224 + @mock.patch.object(thumbor.server, 'which') 225 + + @nottest 226 + def test_validate_null_gifsicle_path(self, which_mock): 227 + server_parameters = mock.Mock(security_key=None) 228 + conf = Config(SECURITY_KEY='test', USE_GIFSICLE_ENGINE=True) 229 + diff --git a/tests/test_utils.py b/tests/test_utils.py 230 + index 38cd51b..7dd0b3e 100644 231 + --- a/tests/test_utils.py 232 + +++ b/tests/test_utils.py 233 + @@ -10,6 +10,7 @@ 234 + 235 + from mock import Mock, patch 236 + from unittest import TestCase 237 + +from nose.tools import nottest 238 + import logging 239 + 240 + from preggy import expect 241 + @@ -112,6 +113,7 @@ class UtilsTestCase(TestCase): 242 + test_func() 243 + mock_warn.assert_called_once_with('Deprecated function test_func: func2') 244 + 245 + + @nottest 246 + def test_can_which_by_path(self): 247 + result = which('/bin/ls') 248 + expect(result).to_equal('/bin/ls') 249 + @@ -119,6 +121,7 @@ class UtilsTestCase(TestCase): 250 + result = which('/tmp') 251 + expect(result).to_be_null() 252 + 253 + + @nottest 254 + def test_can_which_by_env(self): 255 + result = which('ls') 256 + expect(result).to_equal('/bin/ls') 257 + diff --git a/thumbor/server.py b/thumbor/server.py 258 + index c75a769..821163b 100644 259 + --- a/thumbor/server.py 260 + +++ b/thumbor/server.py 261 + @@ -89,12 +89,7 @@ def validate_config(config, server_parameters): 262 + warnings.simplefilter('error', Image.DecompressionBombWarning) 263 + 264 + if config.USE_GIFSICLE_ENGINE: 265 + - server_parameters.gifsicle_path = which('gifsicle') 266 + - if server_parameters.gifsicle_path is None: 267 + - raise RuntimeError( 268 + - 'If using USE_GIFSICLE_ENGINE configuration to True, the `gifsicle` binary must be in the PATH ' 269 + - 'and must be an executable.' 270 + - ) 271 + + server_parameters.gifsicle_path = '@gifsicle@' 272 + 273 + 274 + def get_context(server_parameters, config, importer): 275 + -- 276 + 2.18.1 277 +
+16 -9
pkgs/development/python-modules/thumbor/default.nix
··· 2 2 , pillow, derpconf, python_magic, libthumbor, webcolors 3 3 , piexif, futures, statsd, thumborPexif, fetchFromGitHub, isPy3k, lib 4 4 , mock, raven, nose, yanc, remotecv, pyssim, cairosvg1, preggy, opencv3 5 - , pkgs, coreutils 5 + , pkgs, coreutils, substituteAll 6 6 }: 7 7 8 8 buildPythonPackage rec { 9 9 pname = "thumbor"; 10 - version = "6.6.0"; 10 + version = "6.7.0"; 11 11 12 12 disabled = isPy3k; # see https://github.com/thumbor/thumbor/issues/1004 13 13 ··· 16 16 owner = pname; 17 17 repo = pname; 18 18 rev = version; 19 - sha256 = "0m4q40fcha1aydyr1khjhnb08cdfma67yxgyhsvwar5a6sl0906i"; 19 + sha256 = "1qv02jz7ivn38dsywp7nxrlflly86x9pm2pk3yqi8m8myhc7lipg"; 20 20 }; 21 21 22 + patches = [ 23 + (substituteAll { 24 + src = ./0001-Don-t-use-which-implementation-to-find-required-exec.patch; 25 + gifsicle = "${pkgs.gifsicle}/bin/gifsicle"; 26 + exiftool = "${pkgs.exiftool}/bin/exiftool"; 27 + jpegtran = "${pkgs.libjpeg}/bin/jpegtran"; 28 + ffmpeg = "${pkgs.ffmpeg}/bin/ffmpeg"; 29 + }) 30 + ]; 31 + 22 32 postPatch = '' 23 33 substituteInPlace "setup.py" \ 24 34 --replace '"argparse",' "" ${lib.optionalString isPy3k ''--replace '"futures",' ""''} ··· 39 49 mock 40 50 yanc 41 51 remotecv 42 - cairosvg1 43 52 raven 44 53 pkgs.redis 45 54 pkgs.glibcLocales 55 + pkgs.gifsicle 46 56 ]; 47 57 48 58 propagatedBuildInputs = [ ··· 58 68 webcolors 59 69 piexif 60 70 statsd 61 - pkgs.exiftool 62 - pkgs.libjpeg 63 - pkgs.ffmpeg 64 - pkgs.gifsicle 71 + cairosvg1 65 72 ] ++ lib.optionals (!isPy3k) [ futures thumborPexif ]; 66 73 67 74 # Remove the source tree before running nosetests because otherwise nosetests ··· 71 78 redis-server --port 6668 --requirepass hey_you & 72 79 rm -r thumbor 73 80 export LC_ALL="en_US.UTF-8" 74 - nosetests -v --with-yanc -s tests/ 81 + nosetests -v --with-yanc -s tests/ -e test_redeye_applied 75 82 ''; 76 83 77 84 meta = with lib; {