diff --git a/pkgs/development/python-modules/gradio/conftest-skip-network-errors.py b/pkgs/development/python-modules/gradio/conftest-skip-network-errors.py new file mode 100644 index 000000000000..4738de317552 --- /dev/null +++ b/pkgs/development/python-modules/gradio/conftest-skip-network-errors.py @@ -0,0 +1,57 @@ +# This is a pytest hook that skips tests that tries to access the network. +# These tests will immediately fail, then get marked as "Expected fail" (xfail). + +from _pytest.runner import pytest_runtest_makereport as orig_pytest_runtest_makereport + +# We use BaseException to minimize the chance it gets caught and 'pass'ed +class NixNetworkAccessDeniedError(BaseException): + pass + +def pytest_runtest_makereport(item, call): + """ + Modifies test results after-the-fact. The function name is magic, see: + https://docs.pytest.org/en/7.1.x/reference/reference.html?highlight=pytest_runtest_makereport#std-hook-pytest_runtest_makereport + """ + + def iterate_exc_chain(exc: Exception): + """ + Recurses through exception chain, yielding all exceptions + """ + yield exc + if getattr(exc, "__context__", None) is not None: + yield from iterate_exc_chain(exc.__context__) + if getattr(exc, "__cause__", None) is not None: + yield from iterate_exc_chain(exc.__cause__) + + tr = orig_pytest_runtest_makereport(item, call) + if call.excinfo is not None: + for exc in iterate_exc_chain(call.excinfo.value): + if isinstance(exc, NixNetworkAccessDeniedError): + tr.outcome, tr.wasxfail = 'skipped', "reason: Requires network access." + if isinstance(exc, FileNotFoundError): # gradio specific + tr.outcome, tr.wasxfail = 'skipped', "reason: Pypi dist bad." + return tr + +# replace network access with exception + +def deny_network_access(*a, **kw): + raise NixNetworkAccessDeniedError + +import httpx +import requests +import socket +import urllib +import urllib3 +import websockets + +httpx.AsyncClient.get = deny_network_access +httpx.AsyncClient.head = deny_network_access +httpx.Request = deny_network_access +requests.get = deny_network_access +requests.head = deny_network_access +requests.post = deny_network_access +socket.socket.connect = deny_network_access +urllib.request.Request = deny_network_access +urllib.request.urlopen = deny_network_access +urllib3.connection.HTTPSConnection._new_conn = deny_network_access +websockets.connect = deny_network_access diff --git a/pkgs/development/python-modules/gradio/default.nix b/pkgs/development/python-modules/gradio/default.nix new file mode 100644 index 000000000000..ffb99d729328 --- /dev/null +++ b/pkgs/development/python-modules/gradio/default.nix @@ -0,0 +1,175 @@ +{ lib +, buildPythonPackage +, fetchPypi +, pythonOlder +, pythonRelaxDepsHook +, writeText + +# pyproject +, hatchling +, hatch-requirements-txt +, hatch-fancy-pypi-readme + +# runtime +, setuptools +, aiofiles +, aiohttp +, altair +, fastapi +, ffmpy +, markdown-it-py +, mdit-py-plugins +, markupsafe +, matplotlib +, numpy +, orjson +, pandas +, pillow +, pycryptodome +, python-multipart +, pydub +, pyyaml +, requests +, uvicorn +, jinja2 +, fsspec +, httpx +, pydantic +, websockets +, typing-extensions + +# check +, pytestCheckHook +, pytest-asyncio +, mlflow +, huggingface-hub +, transformers +, wandb +, respx +, scikit-image +, ipython +, ffmpeg +, vega_datasets +, boto3 +}: + +buildPythonPackage rec { + pname = "gradio"; + version = "3.20.1"; + format = "pyproject"; + + disabled = pythonOlder "3.7"; + + # We use the Pypi release, as it provides prebuilt webui assets, + # and has more frequent releases compared to github tags + src = fetchPypi { + inherit pname version; + hash = "sha256-oG97GwehyBWjWXzDqyfj+x2mAfM6OQhYKdA3j0Rv8Vs="; + }; + + pythonRelaxDeps = [ + "mdit-py-plugins" + ]; + + nativeBuildInputs = [ + pythonRelaxDepsHook + hatchling + hatch-requirements-txt + hatch-fancy-pypi-readme + ]; + + propagatedBuildInputs = [ + setuptools # needs pkg_resources + aiofiles + aiohttp + altair + fastapi + ffmpy + markdown-it-py + mdit-py-plugins + markupsafe + matplotlib + numpy + orjson + pandas + pillow + pycryptodome + python-multipart + pydub + pyyaml + requests + uvicorn + jinja2 + fsspec + httpx + pydantic + websockets + typing-extensions + ] ++ markdown-it-py.optional-dependencies.linkify; + + nativeCheckInputs = [ + pytestCheckHook + pytest-asyncio + mlflow + #comet-ml # FIXME: enable once packaged + huggingface-hub + transformers + wandb + respx + scikit-image + ipython + ffmpeg + vega_datasets + boto3 + # shap is needed as well, but breaks too often + ]; + + # Add a pytest hook skipping tests that access network, marking them as "Expected fail" (xfail). + # We additionally xfail FileNotFoundError, since the gradio devs often fail to upload test assets to pypi. + preCheck = let + in '' + export HOME=$TMPDIR + cat ${./conftest-skip-network-errors.py} >> test/conftest.py + ''; + + disabledTests = [ + # Actually broken + "test_mount_gradio_app" + + # FIXME: enable once comet-ml is packaged + "test_inline_display" + "test_integration_comet" + + # Flaky, tries to pin dependency behaviour. Sensitive to dep versions + # These error only affect downstream use of the check dependencies. + "test_no_color" + "test_in_interface_as_output" + "test_should_warn_url_not_having_version" + + # Flaky, unknown reason + "test_in_interface" + + # shap is too often broken in nixpkgs + "test_shapley_text" + ]; + disabledTestPaths = [ + # makes pytest freeze 50% of the time + "test/test_interfaces.py" + ]; + #pytestFlagsArray = [ "-x" "-W" "ignore" ]; # uncomment for debugging help + + # check the binary works outside the build env + doInstallCheck = true; + postInstallCheck = '' + env --ignore-environment $out/bin/gradio --help >/dev/null + ''; + + pythonImportsCheck = [ "gradio" ]; + + meta = with lib; { + homepage = "https://www.gradio.app/"; + description = "Python library for easily interacting with trained machine learning models"; + license = licenses.asl20; + maintainers = with maintainers; [ pbsds ]; + }; +} diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index b391d4b86483..8f3191230641 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -4475,6 +4475,8 @@ self: super: with self; { gradient_statsd = callPackage ../development/python-modules/gradient_statsd { }; + gradio = callPackage ../development/python-modules/gradio { }; + grammalecte = callPackage ../development/python-modules/grammalecte { }; grandalf = callPackage ../development/python-modules/grandalf { };