diff --git a/pkgs/development/python-modules/gradio/client.nix b/pkgs/development/python-modules/gradio/client.nix index d1f5af6a6332..6a63952ab6f3 100644 --- a/pkgs/development/python-modules/gradio/client.nix +++ b/pkgs/development/python-modules/gradio/client.nix @@ -2,7 +2,6 @@ lib, stdenv, buildPythonPackage, - nix-update-script, jq, # build-system @@ -32,7 +31,7 @@ buildPythonPackage (finalAttrs: { pname = "gradio-client"; - version = "2.3.0"; + version = "2.5.0"; pyproject = true; # no tests on pypi diff --git a/pkgs/development/python-modules/gradio/default.nix b/pkgs/development/python-modules/gradio/default.nix index 1bbdae5bdc98..073163aa7a8b 100644 --- a/pkgs/development/python-modules/gradio/default.nix +++ b/pkgs/development/python-modules/gradio/default.nix @@ -21,14 +21,13 @@ pnpmConfigHook, # dependencies - aiofiles, anyio, audioop-lts, brotli, fastapi, - ffmpy, gradio-client, groovy, + hf-gradio, httpx, huggingface-hub, jinja2, @@ -82,17 +81,23 @@ let in buildPythonPackage (finalAttrs: { pname = "gradio"; - version = "6.9.0"; + version = "6.19.0"; pyproject = true; + __structuredAttrs = true; src = fetchFromGitHub { owner = "gradio-app"; repo = "gradio"; tag = "gradio@${finalAttrs.version}"; - hash = "sha256-iGaUiJto/tquCSa6D/wbkNyVtK/2kZB/hz62STfwLOY="; + hash = "sha256-9vO+cuxpXERD/rH8wMuNWBNSH6Mu+yZLQMxLoiUTKtk="; }; patches = [ + # Upstream's after_build.js runs `npm install --production` to vendor http-proxy into the server + # build output, which fails offline. + # Copy it (and its dependency closure) from the already-fetched pnpm workspace. + ./dont-npm-install-http-proxy.patch + ./fix-transformers-pipelines-imports.patch ]; @@ -103,8 +108,12 @@ buildPythonPackage (finalAttrs: { src ; inherit pnpm; - fetcherVersion = 3; - hash = "sha256-pZCYtWFNlrcRFomx6HbO0zySOyifO3n/ffzx59pS/A8="; + fetcherVersion = 4; + hash = "sha256-xCxr/jnp9emeB6THGt4cumvApw6fSZQwG2NGOcvR0yQ="; + }; + + env = { + CI = "true"; }; nativeBuildInputs = [ @@ -121,19 +130,13 @@ buildPythonPackage (finalAttrs: { hatch-fancy-pypi-readme ]; - pythonRelaxDeps = [ - "aiofiles" - "tomlkit" - ]; - dependencies = [ - aiofiles anyio brotli fastapi - ffmpy gradio-client groovy + hf-gradio httpx huggingface-hub jinja2 @@ -397,13 +400,25 @@ buildPythonPackage (finalAttrs: { pythonImportsCheck = [ "gradio" ]; + __darwinAllowLocalNetworking = true; + # Cyclic dependencies are fun! - # This is gradio without gradio-client and gradio-pdf + # This is gradio without gradio-client and hf-gradio passthru = { sans-reverse-dependencies = (gradio.override { gradio-client = null; gradio-pdf = null; + # gradio imports hf_gradio at module load (gradio/routes.py), so we must keep it for the + # import to succeed. + # hf-gradio depends on gradio-client, whose test suite pulls in + # gradio.sans-reverse-dependencies, which would create a build cycle. + # Break it by giving hf-gradio a checkless gradio-client. + hf-gradio = hf-gradio.override { + gradio-client = gradio-client.overridePythonAttrs { + doCheck = false; + }; + }; }).overridePythonAttrs (old: { pname = old.pname + "-sans-reverse-dependencies"; diff --git a/pkgs/development/python-modules/gradio/dont-npm-install-http-proxy.patch b/pkgs/development/python-modules/gradio/dont-npm-install-http-proxy.patch new file mode 100644 index 000000000000..b25b851ea2aa --- /dev/null +++ b/pkgs/development/python-modules/gradio/dont-npm-install-http-proxy.patch @@ -0,0 +1,44 @@ +--- a/js/app/after_build.js 2026-05-28 14:03:04.411110834 +0000 ++++ b/js/app/after_build.js 2026-05-28 14:03:32.000852551 +0000 +@@ -1,7 +1,7 @@ +-import { writeFileSync, copyFileSync } from "fs"; ++import { writeFileSync, copyFileSync, cpSync, mkdirSync, readFileSync } from "fs"; + import { resolve, dirname } from "path"; + import { fileURLToPath } from "url"; +-import { execSync } from "child_process"; ++import { createRequire } from "module"; + + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); +@@ -20,8 +20,29 @@ + ) + ); + +-// Install http-proxy in the build output so it's available at runtime +-execSync("npm install --production", { cwd: out_path, stdio: "inherit" }); ++// Vendor http-proxy and its production dependency closure into the build ++// output so it's available at runtime. Upstream runs `npm install --production` ++// here, but the packages are already present in the workspace, so we copy them ++// instead of hitting the network. ++const out_node_modules = resolve(out_path, "node_modules"); ++mkdirSync(out_node_modules, { recursive: true }); ++ ++const copied = new Set(); ++function vendor(name, parentRequire) { ++ if (copied.has(name)) return; ++ copied.add(name); ++ const pkgJsonPath = parentRequire.resolve(`${name}/package.json`); ++ cpSync(dirname(pkgJsonPath), resolve(out_node_modules, name), { ++ recursive: true, ++ dereference: true ++ }); ++ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf8")); ++ const ownRequire = createRequire(pkgJsonPath); ++ for (const dep of Object.keys(pkgJson.dependencies || {})) { ++ vendor(dep, ownRequire); ++ } ++} ++vendor("http-proxy", createRequire(import.meta.url)); + + // Replace the adapter-generated index.js with our custom proxy entry point + copyFileSync( diff --git a/pkgs/development/python-modules/gradio/fix-transformers-pipelines-imports.patch b/pkgs/development/python-modules/gradio/fix-transformers-pipelines-imports.patch index 72fc44d0d3aa..696ea3e569d5 100644 --- a/pkgs/development/python-modules/gradio/fix-transformers-pipelines-imports.patch +++ b/pkgs/development/python-modules/gradio/fix-transformers-pipelines-imports.patch @@ -14,10 +14,10 @@ index 1903f758f..c40e6d3b1 100644 - FillMaskPipeline, - ImageClassificationPipeline, - ObjectDetectionPipeline, -- QuestionAnsweringPipeline, +- QuestionAnsweringPipeline, # ty: ignore[unresolved-import] - TextClassificationPipeline, - TextGenerationPipeline, -- VisualQuestionAnsweringPipeline, +- VisualQuestionAnsweringPipeline, # ty: ignore[unresolved-import] - ZeroShotClassificationPipeline, -) diff --git a/pkgs/development/python-modules/hf-gradio/default.nix b/pkgs/development/python-modules/hf-gradio/default.nix new file mode 100644 index 000000000000..7dfd59ce40a9 --- /dev/null +++ b/pkgs/development/python-modules/hf-gradio/default.nix @@ -0,0 +1,48 @@ +{ + lib, + buildPythonPackage, + fetchPypi, + + # build-system + hatchling, + + # dependencies + gradio-client, + typer, +}: + +buildPythonPackage (finalAttrs: { + pname = "hf-gradio"; + version = "0.4.1"; + pyproject = true; + __structuredAttrs = true; + + # No tags on GitHub + # https://github.com/gradio-app/hf-gradio/issues/2 + src = fetchPypi { + pname = "hf_gradio"; + inherit (finalAttrs) version; + hash = "sha256-oBfZQmGPDUlaWO5FYwR/oEvvYUwA4Mt4mpptBjPP+ns="; + }; + + build-system = [ + hatchling + ]; + + dependencies = [ + gradio-client + typer + ]; + + # The PyPI sdist ships no test suite. + doCheck = false; + + pythonImportsCheck = [ "hf_gradio" ]; + + meta = { + description = "Extension of the Hugging Face CLI for interacting with Gradio Spaces and Apps"; + homepage = "https://pypi.org/project/hf-gradio"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ GaetanLepage ]; + }; +}) diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 9033e7b92583..15ee04f1f391 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -7234,6 +7234,8 @@ self: super: with self; { hexdump = callPackage ../development/python-modules/hexdump { }; + hf-gradio = callPackage ../development/python-modules/hf-gradio { }; + hf-transfer = callPackage ../development/python-modules/hf-transfer { }; hf-xet = callPackage ../development/python-modules/hf-xet { };