Loading pkgs/development/python-modules/gradio/default.nix +18 −21 Original line number Diff line number Diff line Loading @@ -79,41 +79,33 @@ let nodejs = nodejs_24; pnpm = pnpm_10.override { inherit nodejs; }; in buildPythonPackage rec { buildPythonPackage (finalAttrs: { pname = "gradio"; version = "6.5.1"; version = "6.8.0"; pyproject = true; src = fetchFromGitHub { owner = "gradio-app"; repo = "gradio"; tag = "gradio@${version}"; hash = "sha256-pIcliKcb1eVVMk0ARzWcZGXc6pmI8mGVAvCJZ0JHXUw="; tag = "gradio@${finalAttrs.version}"; hash = "sha256-ZHglnRs0AXCu9HlVoSO0h5p6SE4al/OLPn0jwZgKVR8="; }; patches = [ ./fix-transformers-pipelines-imports.patch ]; pnpmDeps = fetchPnpmDeps { inherit inherit (finalAttrs) pname pnpm version src ; inherit pnpm; fetcherVersion = 3; hash = "sha256-6Cx0hdVd0srhArvck2Kn9U2fT7aKtTZjgV5b/Usrnoo="; }; pythonRelaxDeps = [ "aiofiles" "gradio-client" "markupsafe" "pydantic" # Requests >=2.11.10,<=2.12.4. Staging has it, master doesn't. ]; pythonRemoveDeps = [ # this isn't a real runtime dependency "ruff" ]; nativeBuildInputs = [ zip nodejs Loading @@ -128,6 +120,10 @@ buildPythonPackage rec { hatch-fancy-pypi-readme ]; pythonRelaxDeps = [ "aiofiles" "tomlkit" ]; dependencies = [ aiofiles anyio Loading Loading @@ -191,7 +187,7 @@ buildPythonPackage rec { # mock calls to `shutil.which(...)` (writeShellScriptBin "npm" "false") ] ++ optional-dependencies.oauth ++ finalAttrs.passthru.optional-dependencies.oauth ++ pydantic.optional-dependencies.email; preBuild = '' Loading @@ -216,6 +212,7 @@ buildPythonPackage rec { # requires network, it caught our xfail exception "test_error_analytics_successful" "TestSnippetExecution" # Flaky, tries to pin dependency behaviour. Sensitive to dep versions # These error only affect downstream use of the check dependencies. Loading Loading @@ -441,9 +438,9 @@ buildPythonPackage rec { meta = { homepage = "https://www.gradio.app/"; changelog = "https://github.com/gradio-app/gradio/releases/tag/gradio@${version}"; changelog = "https://github.com/gradio-app/gradio/releases/tag/${finalAttrs.src.tag}"; description = "Python library for easily interacting with trained machine learning models"; license = lib.licenses.asl20; maintainers = with lib.maintainers; [ pbsds ]; }; } }) pkgs/development/python-modules/gradio/fix-transformers-pipelines-imports.patch 0 → 100644 +162 −0 Original line number Diff line number Diff line diff --git a/test/test_pipelines.py b/test/test_pipelines.py index 1903f758f..c40e6d3b1 100644 --- a/test/test_pipelines.py +++ b/test/test_pipelines.py @@ -3,20 +3,6 @@ from unittest.mock import MagicMock import pytest import transformers -from transformers import ( - AudioClassificationPipeline, - AutomaticSpeechRecognitionPipeline, - DocumentQuestionAnsweringPipeline, - FeatureExtractionPipeline, - FillMaskPipeline, - ImageClassificationPipeline, - ObjectDetectionPipeline, - QuestionAnsweringPipeline, - TextClassificationPipeline, - TextGenerationPipeline, - VisualQuestionAnsweringPipeline, - ZeroShotClassificationPipeline, -) import gradio as gr from gradio.pipelines_utils import ( @@ -24,6 +10,14 @@ from gradio.pipelines_utils import ( ) +def _get_pipeline_cls(name: str): + """Resolve a pipeline class by name from transformers, returning None if it + was removed in the installed version.""" + return getattr(transformers, name, None) or getattr( + transformers.pipelines, name, None + ) + + @pytest.mark.flaky def test_interface_in_blocks(): pipe1 = transformers.pipeline(model="deepset/roberta-base-squad2") # type: ignore @@ -50,50 +44,66 @@ def test_transformers_load_from_pipeline(): class TestHandleTransformersPipelines(unittest.TestCase): + def _require(self, name: str): + """Return the pipeline class or skip the test if it was removed.""" + cls = _get_pipeline_cls(name) + if cls is None: + self.skipTest( + f"{name} not available in transformers {transformers.__version__}" + ) + return cls + def test_audio_classification_pipeline(self): - pipe = MagicMock(spec=AudioClassificationPipeline) + cls = self._require("AudioClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Class" def test_automatic_speech_recognition_pipeline(self): - pipe = MagicMock(spec=AutomaticSpeechRecognitionPipeline) + cls = self._require("AutomaticSpeechRecognitionPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Output" def test_object_detection_pipeline(self): - pipe = MagicMock(spec=ObjectDetectionPipeline) + cls = self._require("ObjectDetectionPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input Image" assert pipeline_info["outputs"].label == "Objects Detected" def test_feature_extraction_pipeline(self): - pipe = MagicMock(spec=FeatureExtractionPipeline) + cls = self._require("FeatureExtractionPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Output" def test_fill_mask_pipeline(self): - pipe = MagicMock(spec=FillMaskPipeline) + cls = self._require("FillMaskPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Classification" def test_image_classification_pipeline(self): - pipe = MagicMock(spec=ImageClassificationPipeline) + cls = self._require("ImageClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input Image" assert pipeline_info["outputs"].label == "Classification" def test_question_answering_pipeline(self): - pipe = MagicMock(spec=QuestionAnsweringPipeline) + cls = self._require("QuestionAnsweringPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Context" @@ -102,21 +112,24 @@ class TestHandleTransformersPipelines(unittest.TestCase): assert pipeline_info["outputs"][1].label == "Score" def test_text_classification_pipeline(self): - pipe = MagicMock(spec=TextClassificationPipeline) + cls = self._require("TextClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Classification" def test_text_generation_pipeline(self): - pipe = MagicMock(spec=TextGenerationPipeline) + cls = self._require("TextGenerationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Output" def test_zero_shot_classification_pipeline(self): - pipe = MagicMock(spec=ZeroShotClassificationPipeline) + cls = self._require("ZeroShotClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Input" @@ -127,7 +140,8 @@ class TestHandleTransformersPipelines(unittest.TestCase): assert pipeline_info["outputs"].label == "Classification" def test_document_question_answering_pipeline(self): - pipe = MagicMock(spec=DocumentQuestionAnsweringPipeline) + cls = self._require("DocumentQuestionAnsweringPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Input Document" @@ -135,7 +149,8 @@ class TestHandleTransformersPipelines(unittest.TestCase): assert pipeline_info["outputs"].label == "Label" def test_visual_question_answering_pipeline(self): - pipe = MagicMock(spec=VisualQuestionAnsweringPipeline) + cls = self._require("VisualQuestionAnsweringPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Input Image" Loading
pkgs/development/python-modules/gradio/default.nix +18 −21 Original line number Diff line number Diff line Loading @@ -79,41 +79,33 @@ let nodejs = nodejs_24; pnpm = pnpm_10.override { inherit nodejs; }; in buildPythonPackage rec { buildPythonPackage (finalAttrs: { pname = "gradio"; version = "6.5.1"; version = "6.8.0"; pyproject = true; src = fetchFromGitHub { owner = "gradio-app"; repo = "gradio"; tag = "gradio@${version}"; hash = "sha256-pIcliKcb1eVVMk0ARzWcZGXc6pmI8mGVAvCJZ0JHXUw="; tag = "gradio@${finalAttrs.version}"; hash = "sha256-ZHglnRs0AXCu9HlVoSO0h5p6SE4al/OLPn0jwZgKVR8="; }; patches = [ ./fix-transformers-pipelines-imports.patch ]; pnpmDeps = fetchPnpmDeps { inherit inherit (finalAttrs) pname pnpm version src ; inherit pnpm; fetcherVersion = 3; hash = "sha256-6Cx0hdVd0srhArvck2Kn9U2fT7aKtTZjgV5b/Usrnoo="; }; pythonRelaxDeps = [ "aiofiles" "gradio-client" "markupsafe" "pydantic" # Requests >=2.11.10,<=2.12.4. Staging has it, master doesn't. ]; pythonRemoveDeps = [ # this isn't a real runtime dependency "ruff" ]; nativeBuildInputs = [ zip nodejs Loading @@ -128,6 +120,10 @@ buildPythonPackage rec { hatch-fancy-pypi-readme ]; pythonRelaxDeps = [ "aiofiles" "tomlkit" ]; dependencies = [ aiofiles anyio Loading Loading @@ -191,7 +187,7 @@ buildPythonPackage rec { # mock calls to `shutil.which(...)` (writeShellScriptBin "npm" "false") ] ++ optional-dependencies.oauth ++ finalAttrs.passthru.optional-dependencies.oauth ++ pydantic.optional-dependencies.email; preBuild = '' Loading @@ -216,6 +212,7 @@ buildPythonPackage rec { # requires network, it caught our xfail exception "test_error_analytics_successful" "TestSnippetExecution" # Flaky, tries to pin dependency behaviour. Sensitive to dep versions # These error only affect downstream use of the check dependencies. Loading Loading @@ -441,9 +438,9 @@ buildPythonPackage rec { meta = { homepage = "https://www.gradio.app/"; changelog = "https://github.com/gradio-app/gradio/releases/tag/gradio@${version}"; changelog = "https://github.com/gradio-app/gradio/releases/tag/${finalAttrs.src.tag}"; description = "Python library for easily interacting with trained machine learning models"; license = lib.licenses.asl20; maintainers = with lib.maintainers; [ pbsds ]; }; } })
pkgs/development/python-modules/gradio/fix-transformers-pipelines-imports.patch 0 → 100644 +162 −0 Original line number Diff line number Diff line diff --git a/test/test_pipelines.py b/test/test_pipelines.py index 1903f758f..c40e6d3b1 100644 --- a/test/test_pipelines.py +++ b/test/test_pipelines.py @@ -3,20 +3,6 @@ from unittest.mock import MagicMock import pytest import transformers -from transformers import ( - AudioClassificationPipeline, - AutomaticSpeechRecognitionPipeline, - DocumentQuestionAnsweringPipeline, - FeatureExtractionPipeline, - FillMaskPipeline, - ImageClassificationPipeline, - ObjectDetectionPipeline, - QuestionAnsweringPipeline, - TextClassificationPipeline, - TextGenerationPipeline, - VisualQuestionAnsweringPipeline, - ZeroShotClassificationPipeline, -) import gradio as gr from gradio.pipelines_utils import ( @@ -24,6 +10,14 @@ from gradio.pipelines_utils import ( ) +def _get_pipeline_cls(name: str): + """Resolve a pipeline class by name from transformers, returning None if it + was removed in the installed version.""" + return getattr(transformers, name, None) or getattr( + transformers.pipelines, name, None + ) + + @pytest.mark.flaky def test_interface_in_blocks(): pipe1 = transformers.pipeline(model="deepset/roberta-base-squad2") # type: ignore @@ -50,50 +44,66 @@ def test_transformers_load_from_pipeline(): class TestHandleTransformersPipelines(unittest.TestCase): + def _require(self, name: str): + """Return the pipeline class or skip the test if it was removed.""" + cls = _get_pipeline_cls(name) + if cls is None: + self.skipTest( + f"{name} not available in transformers {transformers.__version__}" + ) + return cls + def test_audio_classification_pipeline(self): - pipe = MagicMock(spec=AudioClassificationPipeline) + cls = self._require("AudioClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Class" def test_automatic_speech_recognition_pipeline(self): - pipe = MagicMock(spec=AutomaticSpeechRecognitionPipeline) + cls = self._require("AutomaticSpeechRecognitionPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Output" def test_object_detection_pipeline(self): - pipe = MagicMock(spec=ObjectDetectionPipeline) + cls = self._require("ObjectDetectionPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input Image" assert pipeline_info["outputs"].label == "Objects Detected" def test_feature_extraction_pipeline(self): - pipe = MagicMock(spec=FeatureExtractionPipeline) + cls = self._require("FeatureExtractionPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Output" def test_fill_mask_pipeline(self): - pipe = MagicMock(spec=FillMaskPipeline) + cls = self._require("FillMaskPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Classification" def test_image_classification_pipeline(self): - pipe = MagicMock(spec=ImageClassificationPipeline) + cls = self._require("ImageClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input Image" assert pipeline_info["outputs"].label == "Classification" def test_question_answering_pipeline(self): - pipe = MagicMock(spec=QuestionAnsweringPipeline) + cls = self._require("QuestionAnsweringPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Context" @@ -102,21 +112,24 @@ class TestHandleTransformersPipelines(unittest.TestCase): assert pipeline_info["outputs"][1].label == "Score" def test_text_classification_pipeline(self): - pipe = MagicMock(spec=TextClassificationPipeline) + cls = self._require("TextClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Classification" def test_text_generation_pipeline(self): - pipe = MagicMock(spec=TextGenerationPipeline) + cls = self._require("TextGenerationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"].label == "Input" assert pipeline_info["outputs"].label == "Output" def test_zero_shot_classification_pipeline(self): - pipe = MagicMock(spec=ZeroShotClassificationPipeline) + cls = self._require("ZeroShotClassificationPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Input" @@ -127,7 +140,8 @@ class TestHandleTransformersPipelines(unittest.TestCase): assert pipeline_info["outputs"].label == "Classification" def test_document_question_answering_pipeline(self): - pipe = MagicMock(spec=DocumentQuestionAnsweringPipeline) + cls = self._require("DocumentQuestionAnsweringPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Input Document" @@ -135,7 +149,8 @@ class TestHandleTransformersPipelines(unittest.TestCase): assert pipeline_info["outputs"].label == "Label" def test_visual_question_answering_pipeline(self): - pipe = MagicMock(spec=VisualQuestionAnsweringPipeline) + cls = self._require("VisualQuestionAnsweringPipeline") + pipe = MagicMock(spec=cls) pipeline_info = handle_transformers_pipeline(pipe) assert pipeline_info is not None assert pipeline_info["inputs"][0].label == "Input Image"