1{
2 lib,
3 stdenv,
4 buildPythonPackage,
5 fetchFromGitHub,
6 writeShellScriptBin,
7 gradio,
8
9 # build-system
10 hatchling,
11 hatch-requirements-txt,
12 hatch-fancy-pypi-readme,
13
14 # web assets
15 zip,
16 nodejs,
17 pnpm_9,
18
19 # dependencies
20 setuptools,
21 aiofiles,
22 anyio,
23 brotli,
24 diffusers,
25 fastapi,
26 ffmpy,
27 gradio-client,
28 groovy,
29 httpx,
30 huggingface-hub,
31 importlib-resources,
32 jinja2,
33 markupsafe,
34 matplotlib,
35 numpy,
36 orjson,
37 packaging,
38 pandas,
39 pillow,
40 polars,
41 pydantic,
42 python-multipart,
43 pydub,
44 pyyaml,
45 safehttpx,
46 semantic-version,
47 typing-extensions,
48 uvicorn,
49 typer,
50 tomlkit,
51
52 # oauth
53 authlib,
54 itsdangerous,
55
56 # tests
57 pytestCheckHook,
58 hypothesis,
59 altair,
60 boto3,
61 docker,
62 gradio-pdf,
63 ffmpeg,
64 ipython,
65 mcp,
66 pytest-asyncio,
67 respx,
68 scikit-image,
69 torch,
70 tqdm,
71 transformers,
72 vega-datasets,
73 writableTmpDirAsHomeHook,
74}:
75
76buildPythonPackage rec {
77 pname = "gradio";
78 version = "5.38.2";
79 pyproject = true;
80
81 src = fetchFromGitHub {
82 owner = "gradio-app";
83 repo = "gradio";
84 tag = "gradio@${version}";
85 hash = "sha256-zKAH/tbF1S+LIi1i+BuKBUWDSI0+Ii5FhsZ3sQaFtto=";
86 };
87
88 pnpmDeps = pnpm_9.fetchDeps {
89 inherit pname version src;
90 fetcherVersion = 1;
91 hash = "sha256-sIEsolHffX3cpAJU79w+ndRY4vvmWLxp2efTryv+j38=";
92 };
93
94 pythonRelaxDeps = [
95 "aiofiles"
96 "markupsafe"
97 ];
98
99 pythonRemoveDeps = [
100 # this isn't a real runtime dependency
101 "ruff"
102 ];
103
104 nativeBuildInputs = [
105 zip
106 nodejs
107 pnpm_9.configHook
108 ];
109
110 build-system = [
111 hatchling
112 hatch-requirements-txt
113 hatch-fancy-pypi-readme
114 ];
115
116 dependencies = [
117 setuptools # needed for 'pkg_resources'
118 aiofiles
119 anyio
120 brotli
121 diffusers
122 fastapi
123 ffmpy
124 gradio-client
125 groovy
126 httpx
127 huggingface-hub
128 importlib-resources
129 jinja2
130 markupsafe
131 matplotlib
132 numpy
133 orjson
134 packaging
135 pandas
136 pillow
137 polars
138 pydantic
139 python-multipart
140 pydub
141 pyyaml
142 safehttpx
143 semantic-version
144 typing-extensions
145 uvicorn
146 typer
147 tomlkit
148 ];
149
150 optional-dependencies.oauth = [
151 authlib
152 itsdangerous
153 ];
154
155 nativeCheckInputs = [
156 altair
157 boto3
158 brotli
159 docker
160 ffmpeg
161 gradio-pdf
162 hypothesis
163 ipython
164 mcp
165 pytest-asyncio
166 pytestCheckHook
167 respx
168 # shap is needed as well, but breaks too often
169 scikit-image
170 torch
171 tqdm
172 transformers
173 vega-datasets
174
175 # mock calls to `shutil.which(...)`
176 (writeShellScriptBin "npm" "false")
177 writableTmpDirAsHomeHook
178 ]
179 ++ optional-dependencies.oauth
180 ++ pydantic.optional-dependencies.email;
181
182 preBuild = ''
183 pnpm build
184 pnpm package
185 '';
186
187 postBuild = ''
188 # SyntaxError: 'await' outside function
189 zip -d dist/gradio-*.whl gradio/_frontend_code/lite/examples/transformers_basic/run.py
190 '';
191
192 # Add a pytest hook skipping tests that access network, marking them as "Expected fail" (xfail).
193 # We additionally xfail FileNotFoundError, since the gradio devs often fail to upload test assets to pypi.
194 preCheck = ''
195 cat ${./conftest-skip-network-errors.py} >> test/conftest.py
196 ''
197 # OSError: [Errno 24] Too many open files
198 + lib.optionalString stdenv.hostPlatform.isDarwin ''
199 ulimit -n 4096
200 '';
201
202 disabledTests = [
203 # Actually broken
204 "test_mount_gradio_app"
205 "test_processing_utils_backwards_compatibility" # type error
206
207 # requires network, it caught our xfail exception
208 "test_error_analytics_successful"
209
210 # Flaky, tries to pin dependency behaviour. Sensitive to dep versions
211 # These error only affect downstream use of the check dependencies.
212 "test_no_color"
213 "test_in_interface_as_output"
214 "test_should_warn_url_not_having_version"
215
216 # Flaky, unknown reason
217 "test_in_interface"
218
219 # shap is too often broken in nixpkgs
220 "test_shapley_text"
221
222 # fails without network
223 "test_download_if_url_correct_parse"
224 "test_encode_url_to_base64_doesnt_encode_errors"
225
226 # flaky: OSError: Cannot find empty port in range: 7860-7959
227 "test_docs_url"
228 "test_orjson_serialization"
229 "test_dataset_is_updated"
230 "test_multimodal_api"
231 "test_examples_keep_all_suffixes"
232 "test_progress_bar"
233 "test_progress_bar_track_tqdm"
234 "test_info_and_warning_alerts"
235 "test_info_isolation[True]"
236 "test_info_isolation[False]"
237 "test_examples_no_cache_optional_inputs"
238 "test_start_server[127.0.0.1]"
239 "test_start_server[[::1]]"
240 "test_single_request"
241 "test_all_status_messages"
242 "test_default_concurrency_limits[not_set-statuses0]"
243 "test_default_concurrency_limits[None-statuses1]"
244 "test_default_concurrency_limits[1-statuses2]"
245 "test_default_concurrency_limits[2-statuses3]"
246 "test_concurrency_limits"
247
248 # tests if pip and other tools are installed
249 "test_get_executable_path"
250
251 # Flaky test (AssertionError when comparing to a fixed array)
252 # https://github.com/gradio-app/gradio/issues/11620
253 "test_auto_datatype"
254 ]
255 ++ lib.optionals stdenv.hostPlatform.isDarwin [
256 # TypeError: argument should be a str or an os.PathLike object where __fspath__ returns a str, not 'NoneType'
257 "test_component_example_values"
258 "test_component_functions"
259 "test_public_request_pass"
260
261 # Failed: DID NOT RAISE <class 'ValueError'>
262 # test.conftest.NixNetworkAccessDeniedError
263 "test_private_request_fail"
264 "test_theme_builder_launches"
265
266 # flaky on darwin (depend on port availability)
267 "test_all_status_messages"
268 "test_async_generators"
269 "test_async_generators_interface"
270 "test_async_iterator_update_with_new_component"
271 "test_concurrency_limits"
272 "test_default_concurrency_limits"
273 "test_default_flagging_callback"
274 "test_end_to_end"
275 "test_end_to_end_cache_examples"
276 "test_event_data"
277 "test_every_does_not_block_queue"
278 "test_example_caching_relaunch"
279 "test_example_caching_relaunch"
280 "test_exit_called_at_launch"
281 "test_file_component_uploads"
282 "test_files_saved_as_file_paths"
283 "test_flagging_does_not_create_unnecessary_directories"
284 "test_flagging_no_permission_error_with_flagging_disabled"
285 "test_info_and_warning_alerts"
286 "test_info_isolation"
287 "test_launch_analytics_does_not_error_with_invalid_blocks"
288 "test_no_empty_audio_files"
289 "test_no_empty_image_files"
290 "test_no_empty_video_files"
291 "test_non_streaming_api"
292 "test_non_streaming_api_async"
293 "test_pil_images_hashed"
294 "test_progress_bar"
295 "test_progress_bar_track_tqdm"
296 "test_queue_when_using_auth"
297 "test_restart_after_close"
298 "test_set_share_in_colab"
299 "test_show_error"
300 "test_simple_csv_flagging_callback"
301 "test_single_request"
302 "test_socket_reuse"
303 "test_start_server"
304 "test_state_holder_is_used_in_postprocess"
305 "test_state_stored_up_to_capacity"
306 "test_static_files_single_app"
307 "test_streaming_api"
308 "test_streaming_api_async"
309 "test_streaming_api_with_additional_inputs"
310 "test_sync_generators"
311 "test_time_to_live_and_delete_callback_for_state"
312 "test_updates_stored_up_to_capacity"
313 "test_varying_output_forms_with_generators"
314 ];
315
316 disabledTestPaths = [
317 # 100% touches network
318 "test/test_networking.py"
319 "client/python/test/test_client.py"
320 # makes pytest freeze 50% of the time
321 "test/test_interfaces.py"
322
323 # Local network tests dependant on port availability (port 7860-7959)
324 "test/test_routes.py"
325
326 # No module named build.__main__; 'build' is a package and cannot be directly executed
327 "test/test_docker/test_reverse_proxy/test_reverse_proxy.py"
328 "test/test_docker/test_reverse_proxy_fastapi_mount/test_reverse_proxy_fastapi_mount.py"
329 "test/test_docker/test_reverse_proxy_root_path/test_reverse_proxy_root_path.py"
330 ];
331
332 disabledTestMarks = [
333 "flaky"
334 ];
335
336 pytestFlags = [
337 "-x" # abort on first failure
338 #"-Wignore" # uncomment for debugging help
339 ];
340
341 # check the binary works outside the build env
342 postCheck = ''
343 env --ignore-environment $out/bin/gradio environment >/dev/null
344 '';
345
346 pythonImportsCheck = [ "gradio" ];
347
348 # Cyclic dependencies are fun!
349 # This is gradio without gradio-client and gradio-pdf
350 passthru.sans-reverse-dependencies =
351 (gradio.override (old: {
352 gradio-client = null;
353 gradio-pdf = null;
354 })).overridePythonAttrs
355 (old: {
356 pname = old.pname + "-sans-reverse-dependencies";
357 pythonRemoveDeps = (old.pythonRemoveDeps or [ ]) ++ [ "gradio-client" ];
358 doInstallCheck = false;
359 doCheck = false;
360 preCheck = "";
361 postInstall = ''
362 shopt -s globstar
363 for f in $out/**/*.py; do
364 cp $f "$f"i
365 done
366 shopt -u globstar
367 '';
368 pythonImportsCheck = null;
369 dontCheckRuntimeDeps = true;
370 });
371
372 meta = {
373 homepage = "https://www.gradio.app/";
374 changelog = "https://github.com/gradio-app/gradio/releases/tag/gradio@${version}";
375 description = "Python library for easily interacting with trained machine learning models";
376 license = lib.licenses.asl20;
377 maintainers = with lib.maintainers; [ pbsds ];
378 };
379}