Gaetan Lepage 2026-05-28 10:01:45 +00:00
commit 3aad7978d0
6 changed files with 126 additions and 18 deletions

View file

@ -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

View file

@ -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";

View file

@ -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(

View file

@ -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,
-)

View file

@ -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 ];
};
})

View file

@ -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 { };