mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-23 11:39:17 +08:00
* enter pre-release mode * Remove deprecated parameters and classes for the 5.0 release (#8797) * 5.0 * add changeset * deprecate more * add changeset * lint * Update rotten-bears-bathe.md * Update icy-clocks-juggle.md * changes * Delete .changeset/icy-clocks-juggle.md * every * more deprecation * deprecate inits * fix * fix func * fix some tests * format * fix more tests * fixes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fix (#8830) * fix * Prevent invalid values from being submitted to dropdown, etc. (#8810) * prevent invalid values * error * add changeset * component * add tests * fix tests * spec ts * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fixes * Remove manual ip address check and launch counter (#8884) * changes * add changeset * hash * changes * remove * changes * rename * internal * changes * remove json path * merge * fix tests --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Remove deprecated documentation (#8940) * remove logoutbutton page * remove huggingfacedatasetsaver * Use HTTP Livestreaming for audio/video streaming out (#8906) * HTTP live streaming * type check * fix code * Fix code * add code * Video demo * Fix tests * Update notebook * Add guide * Fix demo * Allow downloading * revert * Fix download filename * lint * notebooks * fix video demo * Fix config * Fix audio repeated play bug * Improve guide * fix audio? * Use cantina * Code * type check * add code * Use runtimeerror * Add code * Adds `strict_cors` parameter to `launch()` (#8959) * prevent null origin requests by default * changes * add changeset * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fi * Streaming out tweaks (#8976) * Tweaks * Better * typo * lint * Improve url downloads for file objects (#8978) * changes * changes * add changeset * add changeset * Ci security tweaks (#9010) * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * asd * change * changes * changes * changes * changes * changes * changes --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: pngwn <hello@pngwn.io> * merge main (#9050) * lint * Have gr.on set value at start as well (#9065) * changes * changes * changes --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> * No token passed by default in `gr.load()` (#9069) * changes * add changeset * docstring * change * client changess --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * changes * Set default `format` in `gr.Audio` to be `None` to avoid unnecessary preprocessing (#9073) * audio format * add changeset * lint * docstring * format * fix tests * tweaks * refactor * fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Streaming inputs for 5.0 (#8941) * Fix code * Add code * Add code * working demo * hacky video * Add code for video * Fixing some code * clean queieing * low streaming mode audio * reworking * remove console * Pretty good spot * Delete unused * consolidate * Add progress bar * Set time limit null * delete * Fix then issue * merge out * Add code * clean up * Remove base64 * Add code * minor bugs * End stream * Fix rerender * remove unwanted * Address streaming comments * Commit file lol * ;int * lint backend * lint * Fix queue status. Stream_every defined in event * Fix types * Add code * Add code * Add code * queue time * docstring wording * Fix typo * add changeset --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * 3.10 (#9133) * Deprecate passing a tuple for gr.Code value (#9132) * Add code * add changeset * lint * type check --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Postprocess hardening (#9122) * hardenning * Fix code * add changeset * Fix tests * add test fuzzer * Clean up * revert * Fix * Add code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Drop python 3.8 and 3.9 (#9140) * drop support for python 3.8 and 3.9 * add changeset * format * changes * add changeset * changes * add changeset * changes * 3.10 * string * tweak * tweak * changes * changes * format * more tweaks * update actions * website docs build * fix func tests * rev req * test fix * remove ruff rule for zip strict --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Raise WasmUnsupportedError for ffmpeg usage on Lite (#9130) * Raise WasmUnsupportedError for ffmpeg usage on Lite * add changeset * add changeset * Add WasmUnsupportedError in Audio._convert_to_adts * Add WasmUnsupportedError in processing_utils.audio_to_file * Fix * Raise WasmUnsupportedError from processing_utils.audio_from_file * empty commit --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Video gallery (#9052) * video support * tests and backend changes * undo main merge * upload fix * Revert "undo main merge" This reverts commite2a26e6d28
. * type fixes * format * pr fixes * Update gradio/components/gallery.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Update gradio/components/gallery.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * type fix * thumbnails * thumbnail type * remove thumbnail generation * add changeset * test fixes * test fixes * python test fix * python test fixc * fix * fix * story fix --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Open audio/image input stream only when queue is ready (#9149) * fix * submit logic happens in Blocks * add changeset * trigger ci * trigger ci * Add code * Add code * Fix retrigger refactor * Add code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * trigger ci * update (#9176) * File access security guide (#9156) * first draft Add code Add code Add code emphasis * suggestions * redirects * add changeset * trigger ci * typos --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fix guide * Fix notebook (#9181) * DNS resolver on ip check (#9150) * changes * changes * add changeset * chaanges * changes * changes * changes * changes * add caching and whitelist * remove hf.space --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Change dark mode color theme from `gray` to `zinc` (#9175) * use zinc as neutral colour * add changeset * fix test * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Streaming Guides (#9173) * Fix unified case * commit * Add code * add changeset * notebook * Lint * delete * Fix code * fix tests * File access security guide (#9156) * first draft Add code Add code Add code emphasis * suggestions * redirects * add changeset * trigger ci * typos --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * redirect * typos * link * fix * See what the problem is * less time * fix * try again with busted cache * try again * Code * Demo and code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: pngwn <hello@pngwn.io> * Fix (#9215) * Deprecate type='tuples for chatbot and focus chatbot docs on 'messages' type (#9194) * Remove grey background behind all components (#9213) * remove panel padding and border * add changeset * revert radius change * add changeset * format * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * changes * changes * Revert "changes" This reverts commit9e2ae43330
. * Revert "changes" This reverts commit9f4c3eec0f
. * Redesign `gr.Slider()` (#9197) * redesign slider * add changeset * fix test * update slider design * slider tweaks --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * 🔡 Update default core Gradio font (#9204) * change sans font from Source Sans Pro to Asap * change misc refs to Source Sans Pro * add changeset * revert old changes * add changeset * replace asap with IBM Plex Sans * add changeset * repalce asaps with ibm plex * tweak --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Redesign `gr.Button()` (#9167) * *add new button styling *add origin theme class with old button styling * add changeset * remove new colour * add changeset * color and radius tweaks * remove neutral hue change * *update button demo *style tweaks * format * fix test * use white text on primary btn * adjust primary orange * tweak colour * disabled fixes * refactor * refactor * refactor * refactor * remove non-button changes * test * revert test * make cancel btn darker in light mode * change button stories to interactive * fix slider test * fix test * tweak * tweak secondary colour to work with gr.group() * add changeset * tweak * tweak button hover grey --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: pngwn <hello@pngwn.io> * Minor changes to flagging for 5.0 (#9166) * init * add changeset * rename * flagging * flagging * changes * update * changes * more * more * changes * add changeset * fix test * changes * update demos --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Adds TLS to FRP tunnel (#9218) * tls tunnel * add changeset * add changeset * arm64 * checksums * changes * tweaks * tweak --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Move buttons from chat_interface into Chatbot (#9201) * First draft * type check * test * add changeset * Fix e2e styling and tests * fix lint * Add code * add changeset * Remove shadow of copy button, make a box * lint * add changeset * fix padding + lint * make buttons a bit smaller. use different icon * Add code * add changeset * tunneling * fix * Add code * fix + lint * Add code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Improve button consistency across light/dark mode (#9236) * ensure btn borders are consistent in light and dark mode * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Redesign `gr.Tabs()` (#9199) * Decrease component radii and remove input shadows (#9216) * fix py chatbot test * Lighten secondary button grey fill (#9245) * lighten secondary button grey * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Stop using `multiprocessing` in `flagging.CSVLogger` on Lite v5 (#9246) * Fix the default demo code for the dev * Use ClassicCSVLogger for Lite * add changeset * add changeset * Revert "Use ClassicCSVLogger for Lite" This reverts commita89fcb1134
. * Avoid using multiprocessing.Lock on Lite * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * prefix api routes (#9200) * Built-in submit and stop buttons in `gr.ChatInterface(multimodal=False)`, adding `submit_btn` and `stop_btn` props to `gr.Textbox()` and `gr.MultimodalText()` (#9235) * Add submit_btn prop to the Textbox component and use it in ChatInterface for a consistent design with multimodal=True * Change the default value of MultimodalTextbox.submit_btn to False for consistency with Textbox.submit_btn * add changeset * Set the default value of Textbox.submit_btn as False for consistency * add changeset * Add stop_btn prop to Textbox and MultimodalTextbox and use it in ChatInterface for a built-in stop button * add changeset * add changeset * Fix Python tests * Fix JS tests * nit fix * Make the submit and stop buttons not exclusive for simplicity * Replace the Pause icon with the Square icon * add changeset * Update the docstring * Preserve the original values of textbox.submit_btn and .stop_btn after running a generator * Show the stop button only when the submit_btn is enabled from the beginning * Respect the user-specified values of submit_btn and stop_btn * Add ChatInterface.submit_btn and .stop_btn params * Fix Textbox.svelte style with string values of submit_btn and stop_btn * Fix Python tests * Fix Python code * fix test * Apply suggestions from code review Co-authored-by: Abubakar Abid <abubakar@huggingface.co> --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Adds a "huggingface" button variant, and makes it the default for `gr.LoginButton` and `gr.DuplicateButton` (#9254) * add clear variant * add changeset * duplicate button * add changeset * tweak * tweak * format * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#8829) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix cs * chore: update versions (beta) (#9262) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Improve Icon Button consistency (#9250) * * update icon buttons * add image editor specific icon button * tweak hover * margin tweak * add changeset * improve gr.Video button UI * radius tweak * ensure even spacing * fix typechecks * add changeset * revert irrelevant changes * typefix * fix image editor buttons * fix download link icon * disable undo if no change events dispatched in model3d and video * add changeset * add iconbuttonwrapper around gallery share btn --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * format * Fix reload mode and streaming in 5.0 dev (#9269) * Fix reload mode + streaming * use api_prefix for reload * add changeset * comments --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Raise error instead of warning if checksums for binary do not match (#9268) * tunneling * add changeset * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix stop recording button colors (#9270) * Add code * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Match style of textbox stop button to submit button (#9280) * Change styles * styling * add changeset * add changeset * consistent width --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Raise ChecksumMismatchError (#9300) * raise mismatch * add changeset * changes * format backend --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Further tweak to is_in_or_equal (#9282) * Add code * add changeset * add changeset * is_launching tweak * no resolve symlink * Use has_launched --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * changes (#9301) * Fixes race condition in `update_root_in_config` (#9306) * test * lint * tests * add changeset * change * lint * reduce num attempts --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * docstring * Adds ability to block event trigger when file is uploading (#9253) * input_ready * add changeset * update value * block event when input waiting * format * add changeset * dep index --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * 5.0 merge (#9318) * merge * pythong format * fix typecheck * fix json scroll * fix test --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Hannah <hannahblair@users.noreply.github.com> * Proposal: remove `gr.make_waveform` and remove `matplotlib` as a dependency (#9312) * remove matplotlib * add changeset * remove tests, demo * Fix the Lite worker to set the matplotlib backend engine only when the matplotlib package is installed * add changeset * Fix comment --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com> * Dont move files to cache automatically in chatbot postprocess (#9303) * Fix * add changeset * Add code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Remove two dependencies: `importlib_resources` and `urllib3` (if not in Wasm) (#9321) * remove-importlib_resources * add changeset * urllib only on wasm * add changeset * format * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Make `gr.Image` preprocessing more efficient (#9314) * image preprocess * add changeset * changes * fix tests * docstring * docstring * image * fix * format * changes * fix test * changes * handle svg files --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * 5.0 merge take 2 (#9326) * chore: update versions (#9168) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * chore: update error.svx (#9291) * chore: update error.svx occured -> occurred * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Update docs to use new Image init (#9304) * Fix scrollbars everywhere (#9276) * changes * add changeset * scroll fix * remove .json css, adjust scroll height to account for label --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Hannah <hannahblair@users.noreply.github.com> * Separate starlette.Request from PredictBody. Only set in new PredictBodyInternal object (#9279) * use custom pydantic type annotatio * add changeset * Add code * add changeset * rework * dont use arbitrary_types_allowed * add changeset * fix test * revert path change --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Add root_url to components created by gr.render (#9267) * Fix bug * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fileformat whitelist (#9302) * changes * add changeset * Update routes.py --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix multiple trigger bug when function has js (#9188) * add code * add changeset * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (#9298) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix json * harden test * harden test * clean * format * add changeset * notebooks * fix old conflicts --------- Co-authored-by: Gradio PR Bot <121576822+gradio-pr-bot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Tayfun Sen <tayfun.sen@gmail.com> Co-authored-by: aliabid94 <aabid94@gmail.com> Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: Hannah <hannahblair@users.noreply.github.com> Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com> * Add `matplotlib` requirements to several demos (#9327) * add matplotlib req to demos * add matplotlib req to demos * more * update reqs * clean * format * Standardize `height` across components and add `max_height` and `min_height` parameters where appropriate (#9313) * height * changelog * height * add changeset * add changeset * add changeset * revert clog * more changes * add changeset * chatbot * restore * filexplorer * add changeset * json * add changeset * markdown * add changeset * row * add changeset * height * format frontend * revert * max height * fix * fix docstrings * fix py tests * add story --------- Co-authored-by: Dawood <dawoodkhan82@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix typo in `tunneling.py` (#9338) * tunneling fix * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Set the color of placeholder in a disabled textbox to gray instead of black, and disable typing while a response is generating in `gr.ChatInterface`, allow `gr.MultimodalTextbox` to accept string values (#9328) * textbox * add changeset * changes' * revert demos * add changeset * add changeset * changes * multimodal * add changeset * changes * format * revert demo * fix test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Improve is_in_or_equal and fuzzer (#9341) * improve fuzzer * test case * add changeset * verify * Update gradio/utils.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Add info about Powershell client (#9343) * clients * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Remove lite/theme.css from the Git-managed file tree (#9335) * Delete js/lite/src/theme.css from the Git managed file tree as it's dynamically generated * Remove lite-related npm scripts from spa/package.json * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * 9227 chatinterface retry bug (#9316) * first draft * add code * tip * add changeset * delete dead code * Type check notebook * consolidate like section with guide * Add comments * add value * Lint * lint * guide --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Move icons into `IconButtonWrapper` (#9261) * * update icon buttons * add image editor specific icon button * tweak hover * margin tweak * add changeset * improve gr.Video button UI * radius tweak * ensure even spacing * fix typechecks * add changeset * revert irrelevant changes * typefix * fix image editor buttons * fix download link icon * disable undo if no change events dispatched in model3d and video * use icons with iconbuttonwrapper * add iconbuttonwrapper around gallery share btn * Revert "add iconbuttonwrapper around gallery share btn" This reverts commit4605302df4
. * add changeset * design fixes * add changeset * move status tracker progress to bottom of component * add changeset * use iconbutton for like/dislike * fix lint error * fix type errors * type errors * fix test * revert undo icon change * btn spacing --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Added gradio-in-r (#9340) * Added gradio-in-r * add changeset * section * remove * tweaks * delete changeset * R * Updated using-gradio-in-other-programming-languages.md --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Enhance Lite E2E tests and fix a networking problem on Lite (#9333) * Add Lite E2E test to check a matplotlib problem which was fixed in https://github.com/gradio-app/gradio/pull/9312 * Restore js/app/test/image_remote_url.spec.ts, which was deleted in https://github.com/gradio-app/gradio/pull/8716 * Fix tootils import * Format * Fix processing_utils.resolve_with_google_dns to use the HTTPX client instead of urllib so it works on Lite * add changeset * add changeset * Move js/app/test/image_remote_url.spec.ts -> js/spa/test/image_remote_url.spec.ts * Use pyodide.http in resolve_with_google_dns on Lite --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Do not attach `content_disposition_type = "attachment"` headers for files explicitly allowed by developer (#9348) * changes * add changeset * format * fix type * type * add test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix overflowing markdown in Chatbot (#9260) * fix markdown overflowing table * add changeset * revert undo icon * add changeset * Revert "revert undo icon" This reverts commit855b012a20
. * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Small tweak to how thoughts are shown in `gr.Chatbot` (#9359) * thiknk chat * add changeset * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Use `container` param in `gr.Markdown` (#9356) * * add param * add story * add changeset * Use IconButton for copy btn * fix test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * run format * Fixes website build in 5.0-dev (#9382) * changes * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Small tweaks to improve the DX for the "tuples"/"messages" argument in `gr.Chatbot` (#9358) * change format * format * add changeset * revert * revert --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Update babylon.js to `v7` for `gr.Model3D` (#9377) * update package.json * add changeset * add changeset * update pnpm lock * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix `gr.ImageEditor` toolbar cutoff (#9371) * fix wrap alignment * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Adds LLM to the Playground (#9233) * simple system prompt * faster model and streaming and better system prompt * changes * changes * add changeset * formatting * add placeholder wheel * changes * save to db finally working * clean * fix open in playground button * better fix for open in playground * changes * format * fix * try * remove * remove make waveform * fix * using fallback mode and other changes * add show_error * fix lite refresh issue * fix css * add demo * format * lite using latest wheel * cleanup * formatting * hack fix for b vs betta * formatting --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Refactor lazy caching (#9361) * changes * lazy * redo lazy * add changeset * changes * helpers * docstrings' * lint * Update guides/04_additional-features/09_environment-variables.md Co-authored-by: Charles <charles@huggingface.co> * Update gradio/chat_interface.py Co-authored-by: Dawood Khan <dawoodkhan82@gmail.com> * Update gradio/chat_interface.py Co-authored-by: Dawood Khan <dawoodkhan82@gmail.com> * tolerant --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Charles <charles@huggingface.co> Co-authored-by: Dawood Khan <dawoodkhan82@gmail.com> * Added max lines and overflow scrollbar for `gr.Code` (#9311) * add max lines for gr.Code * add changeset * revert default lines to 5 * fix tests * lint --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix File Types for MultimodalTextbox (#9393) * fix file_types * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Prevent HTML and Markdown height changing when status is hidden (#9363) * fix markdown height changing * * add min_height param to html * prevent height from changing based on status * add changeset * add changeset * param desc change * fix test * format * * add max height to html * share css_units func * add changeset * fix backend test * fe --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Object Detection From Webcam Stream Guide (#9336) * guides * Add demo * guide * Add info about Powershell client (#9343) * clients * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Remove lite/theme.css from the Git-managed file tree (#9335) * Delete js/lite/src/theme.css from the Git managed file tree as it's dynamically generated * Remove lite-related npm scripts from spa/package.json * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * 9227 chatinterface retry bug (#9316) * first draft * add code * tip * add changeset * delete dead code * Type check notebook * consolidate like section with guide * Add comments * add value * Lint * lint * guide --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Move icons into `IconButtonWrapper` (#9261) * * update icon buttons * add image editor specific icon button * tweak hover * margin tweak * add changeset * improve gr.Video button UI * radius tweak * ensure even spacing * fix typechecks * add changeset * revert irrelevant changes * typefix * fix image editor buttons * fix download link icon * disable undo if no change events dispatched in model3d and video * use icons with iconbuttonwrapper * add iconbuttonwrapper around gallery share btn * Revert "add iconbuttonwrapper around gallery share btn" This reverts commit4605302df4
. * add changeset * design fixes * add changeset * move status tracker progress to bottom of component * add changeset * use iconbutton for like/dislike * fix lint error * fix type errors * type errors * fix test * revert undo icon change * btn spacing --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Added gradio-in-r (#9340) * Added gradio-in-r * add changeset * section * remove * tweaks * delete changeset * R * Updated using-gradio-in-other-programming-languages.md --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Enhance Lite E2E tests and fix a networking problem on Lite (#9333) * Add Lite E2E test to check a matplotlib problem which was fixed in https://github.com/gradio-app/gradio/pull/9312 * Restore js/app/test/image_remote_url.spec.ts, which was deleted in https://github.com/gradio-app/gradio/pull/8716 * Fix tootils import * Format * Fix processing_utils.resolve_with_google_dns to use the HTTPX client instead of urllib so it works on Lite * add changeset * add changeset * Move js/app/test/image_remote_url.spec.ts -> js/spa/test/image_remote_url.spec.ts * Use pyodide.http in resolve_with_google_dns on Lite --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Do not attach `content_disposition_type = "attachment"` headers for files explicitly allowed by developer (#9348) * changes * add changeset * format * fix type * type * add test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix overflowing markdown in Chatbot (#9260) * fix markdown overflowing table * add changeset * revert undo icon * add changeset * Revert "revert undo icon" This reverts commit855b012a20
. * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * demo name * Guide on Streaming Video for Object Detection (#9365) * Add code * notebooks * Suggestions * Add gif * Small tweak to how thoughts are shown in `gr.Chatbot` (#9359) * thiknk chat * add changeset * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Use `container` param in `gr.Markdown` (#9356) * * add param * add story * add changeset * Use IconButton for copy btn * fix test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * small fixes (#9347) * Updated Guide: Real Time Speech Recognition (#9349) * Update real-time-speech-recognition.md added necessary dependency * Update run.py updated code to handle cases with stereo microphone * Update real-time-speech-recognition.md improved english * Update run.py updated code for streaming * Update run.py * chunk space uploads (#9360) * chunk space uploads * Update upload_demo_to_space.py Co-authored-by: Lucain <lucainp@gmail.com> * address comments + tweak CI --------- Co-authored-by: Lucain <lucainp@gmail.com> * add find (#9368) * New branch (#9369) * add find * fix syntax * New branch (#9370) * add find * fix syntax * add hidden files * run format * Testing CI (#9379) * remove unnecessary redirects * add changeset * fix * formatting --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fixes website build in 5.0-dev (#9382) * changes * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Small tweaks to improve the DX for the "tuples"/"messages" argument in `gr.Chatbot` (#9358) * change format * format * add changeset * revert * revert --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Update babylon.js to `v7` for `gr.Model3D` (#9377) * update package.json * add changeset * add changeset * update pnpm lock * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix `gr.ImageEditor` toolbar cutoff (#9371) * fix wrap alignment * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * add lite upload (#9385) * fix sha (#9386) * Fix lite ci (#9387) * fix sha * fix name * fix name * Add code * feedback * link * add changeset * code * check * Update guides/04_additional-features/02_streaming-outputs.md * Update guides/07_streaming/02_object-detection-from-webcam.md --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com> Co-authored-by: Hannah <hannahblair@users.noreply.github.com> Co-authored-by: Ifeanyi Idiaye <72707830+Ifeanyi55@users.noreply.github.com> Co-authored-by: Julien Chaumond <julien@huggingface.co> Co-authored-by: Nikita Krasnytskyi <nikita.kras.kyiv@gmail.com> Co-authored-by: pngwn <hello@pngwn.io> Co-authored-by: Lucain <lucainp@gmail.com> Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com> * Fix gradio.js aws path (#9397) * fix folder path for beta * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Trigger state change event on iterators (#9299) * Fix render async * add changeset * Fix regression * tests * Add code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * add local fonts and update themes (#9367) * add local fonts and update themes * add changeset * tweak * - dedent css - fix if logic * store theme fonts locally + update themes with `LocalFont` * lint * fix font loading --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com> * Disable liking user message in chatbot by default but make it configurable (#9323) * Code * add changeset * revert * test" " * typo * Fix code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix Cached Examples for Streamed Media (#9373) * fix problem * add changeset * gitignore * lint * Add code * Add code * Fix extension * add changeset * unit test * typecheck * typecheck * lint * test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fixes annoying height bug in playground (#9402) * fix styling issue * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Chatbot Examples (#8966) * examples * examples * first pass * remove comments * remove comments * add changeset * Fix chatinterface e2e test (#9104) * Refactor test * comment * Fix image * add changeset * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fix version + pkg name (#9110) * fix version + pkg name * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fix dev (#9115) * fix asset locations * fix changeset * Be able to set optimizeDeps options in gradio.config.js (#9091) * Add code * add changeset * build * Remove unused import --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Better text styling on docs (#9108) * margin and size * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * setup npm-previews of all packages (#9118) * add workflow * fix pkg jsons * workflow name * add changeset * fix * add changeset * fix build command --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix chatinterface multimodal bug (#9119) * Add test * add changeset * comments --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chatbot examples * examples changes * chatinterface * chatinterface * pr fixes * remove html demo change * suggestion width * type fixes * format * comment our examples test * remove cache * comment example caching test * bug fix * bug fix * format * type fix * Proposal: remove `gr.make_waveform` and remove `matplotlib` as a dependency (#9312) * remove matplotlib * add changeset * remove tests, demo * Fix the Lite worker to set the matplotlib backend engine only when the matplotlib package is installed * add changeset * Fix comment --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com> * Dont move files to cache automatically in chatbot postprocess (#9303) * Fix * add changeset * Add code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * test fix * format * changes * update guide * cache examples * add changeset * format * changes * changes * changes * changes * changes * changes * format * fixes * test chat interface fixes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com> Co-authored-by: pngwn <hello@pngwn.io> Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com> Co-authored-by: Ali Abid <aliabid94@gmail.com> * Ssr part 2 (#9339) * chore: update versions (beta) (#9263) * Center icon in button when no text is present (#9405) * center button when only icon is present * add changeset * format * add story --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fix SSR apps on spaces (#9412) * test * add changeset * test * test * test * fix? * fix? * add changeset * fix * fix * fix * fix * fix finally? * fix * add changeset * lints etc * add changeset * remove spa mode * fix env * typing * change * lint * remove node logs * remove node logs --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Small fixes to `gr.Dataframe` and chatbot docs (#9376) * docs * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#9416) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Allow skipping an arbitrary number of output components, and also raise a warning if the number of output components does not match the number of values returned from a function (#9406) * demo * add warnings * add changeset * add changeset * add doc section * format * fix check * fix typing issues * docs * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * fix css (#9427) * fix css * add changeset * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Dawood <dawoodkhan82@gmail.com> * Fix Python unit tests on `5.0-dev` branch (#9432) * fix python unit tests * changes * changes * fix * Lite: HTTPX client improvement (#9413) * Use the httpx client in resolve_with_google_dns both for normal and Lite * add changeset * Set decode_content=False * Add type hints * Set decode_content=True and remove the Content-Encoding header so the content is decoded by urllib3 instead of httpx * Fix * Add comment * Restore the original resolve_with_google_dns to make such changes in another PR * add changeset * Update comment * Updated the test requirements * Fix type hint * Revert "Updated the test requirements" This reverts commit2e43584a87
. --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Use or `pathlib.Path` objects to indicate filepaths for `css`, `js`, and `head` parameters (#9448) * format * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Reduce analytics that are collected (#9447) * reduce analytics collected * analytics * add changeset * bring back css --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix SSR mode flag with `mount_gradio_app` and revert changes to pytests (#9446) * Revert "Fix Python unit tests on `5.0-dev` branch (#9432)" This reverts commit278645b649
. * revert changes to pytest * add changeset * fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Small changes to caching (#9438) * caching changes * add changeset * typo * typo * changes * fix * fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Refactoring playground (#9426) * Use @gradio/code.BaseCode instead of its default export like https://github.com/gradio-app/gradio/pull/8804 * Delete unused code * add changeset * Fix * Rename a variable to be descriptive * Mount single <Code> instance instead of creating one for each demo * Fix the initial value passed to createGradioApp * Use const instead of let * Rename variable * Update * Fix layout * Restore the preset requirements * Delete unused variable * Add type hint * Attach the keydown handler directly to the input element instead of the window object * Add code editor widget --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Chatbot bug fixes (#9453) * image fixes * add changeset * more fixes * fix * fix * css fixes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Update object detection guide (#9456) * First draft * Add code * update guide * add changeset * revert * edits * Add code * notebooks * fix code --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Start/stop recoding from the backend. Add guide on conversational chatbots (#9419) * Add code * stop displatch * first draft * edit * add changeset * lint * Docstring * Make recording * fix video * fix guide link * redirect * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Improve UI on the Playground (#9462) * ai prompt always there * fix overflow * better ui and suggested prompts * cancel generation and showing erro * formatting * add changeset * fix height issue and button * changes * fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix. Triggered dataframe change event for header change (#9469) * Fix. Triggered dataframe change event for header change * add changeset * lint * add changeset --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#9420) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * format * Fix package.json `exports` of @gradio/preview (#9468) * Fix package.json exports of @gradio/preview * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Fix plots (#9464) * fix * add changeset * lint * clean * ts * format * add changeset * format * remove test that is wrong * fixxxxxx * add changeset * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Pre/post-processing download requests (#9383) * changes * add changeset * changes * change * changes * changes * changes * changes * change * changes * changes * changes * changes * changes * changes * changes * Update gradio/processing_utils.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * changes * changes * changes * changes * changes * changes * Fix Lite's ASGI receiver to convert memoryview to bytes as the multipart parser called in98cbcaef82/gradio/route_utils.py (L650)
calls bytes.find() and memoryview objects don't have the method * add changeset * Fix async_get_with_secure_transport to use the unsecure but Pyodide-compatible transport in the case of Wasm --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com> * Add support for 3rd party providers to `gr.load`, and provide a better UX for conversational models (#9470) * changes * add changeset * changes * changes * docstring * chatbot * changes * fix test * format * add changeset * update req * remove conversational * add changeset * remove args --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#9476) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Fix `slider-color` var (#9481) * fix slider-color * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Playground requirements tab (#9460) * Add a tab navigation to the playground so the user can specify the requirement packages * Add Transformers.js.py demo and fix the playground to install the requirements immediately after switching the demo * add changeset * Format * add changeset * Fix preview flex * Add requirements to the share link and deploy to Spaces buttons * Add requirements.txt to each demo * Format * Update notebooks * Fix * Update --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: aliabd <ali.si3luwa@gmail.com> * Fix prettierignore (#9486) * Minor fixes to docs and a demo (#9493) * small things * docstring * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Check for `file_types` parameter in the backend (#9431) * file check fix * format * add changeset * tests * add changeset * Update gradio/components/file.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Update client/python/gradio_client/utils.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * fixes * fixes * test fix * test fix * test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Ensure media queries work for SSR mode (#9428) * asd * asd * fix * add changeset * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Fix custom component CLI unit tests (#9495) * fix * fix audio test * fix template * add changeset --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fixes: Chatbot examples for custom chatbot + rename `suggestions` -> `examples` (#9488) * fix * add changeset * notebooks * fixes * fix * type fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * UI theme fixes (#9496) * changes * add changeset * changes * changes * add changeset * changes --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Centre components within `Block` when height and width are set (#9504) * add centering margin * add changeset * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Improve `gr.Code` (#9450) * fix check icon on download * * apply unused min_width param * improve gutter spacing * hide `BlockLabel` spacing if `show_label` is false * format * tweak spacing, remove `fit-content` * add changeset * revert height change * fix * allow setting max_lines to None * add line wrapping * add wrap lines param * fix type error * fix py test * fix type check --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix node process to run with correct server name (#9506) * fix node process * add changeset * add changeset * format * cleanup --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * yaml lint * Add Bokeh plot demo (#9423) * Add Bokeh plot demo * Update notebook --------- Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Expanding AI Playground Prompt for Qwen (#9452) * expand prompt for qwen * add changeset * clean * add changeset * heavily modify prompt * changes * many changes * fix weird syntax error * fix * ? * changes * fix requirements * formatting --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * docs: update 01_quickstart.md (#9515) arbitary -> arbitrary Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Fix change triggers for dropdown and radio (#9519) * fix change triggers * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#9485) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Fix single select dropdown (#9526) * Set the default value of Dropdown as undefined instead of [] when multiselect=false * Refactoring * add changeset * Fix tests --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Hide x axis labels (#9497) * changes * add changeset * fix --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Add Jinja2 language to Code component (#9545) * Add jinja2 codemirror language * add jinja2 * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Disable sagemaker_check() for now (#9546) * Add is_sagemaker param to Blocks, so sagemaker_check() can be explicitly disabled * revert * add changeset * format * add changeset --------- Co-authored-by: Mate Valko <> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#9544) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Update gr.ColorPicker UI (#9570) * update color picker dialog * add changeset * add tinycolor types * fix disabled param * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix cut off in gr.ImageEditor (#9525) * remove default height value * remove canvas w x h * revert comment * add changeset * add changeset * fix stage-wrap shift * empty tweak * add changeset * tweak * type fix * test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Change caching to occur not at the creation of a `gr.Examples()` but when the Blocks is actually launched (#9508) * changes * changes * add changeset * await * add changeset * changes * changes * changes * changes --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Add `css_paths` and `head_paths` parameters (#9524) * paths * add changeset * changes * fixes * add new lines * remove js_paths * add changeset * format --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix most flaky Python tests in `5.0-dev` branch (#9550) * fix flaky tests * add changeset * token * changes * fixes * hf token * format * test * format * root url * format * fix * fix tests * add changeset * remove huggingface hub fixed version * add changeset * remove print --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Api info fix (#9522) * api-info-fix * add changeset * Add with fallback * route utils * update --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Send Streaming data over Websocket if possible. Also support base64 output format for images. (#9483) * b64 first draft * ws * onMount + demos and guide * guide * add changeset * Add code * lint * type check * Have a fallback * Add code * delete unneccessary input * API info tweaks * Revert type param type hint * Add code * api-info-fix * add changeset * Add with fallback * route utils * update * final tweaks * type check * fix * add changeset * fix * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Allow `info=` to render markdown (#9521) * allow info to render markdown * add changeset * update docstrings * format * fixes * add changeset * fix * add changeset * root * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Equal height columns (#9577) * changes * add changeset * add changeset --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix chatinterface embedding height issues (#9571) * changes * add changeset * changes * changes * lint --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * chore: update versions (beta) (#9572) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Update gr.Dataframe UI with action popover (#9575) * add dialog for actions * add changeset * add story * add changeset * * remove temp select column * change open dialog UX in mobile * fix border * fix test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Disable the submit button and enter-key submit when the text is empty (#9583) * Disable the submit button and enter-key submit when the text is empty * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Chat Interface Multimodal Fix & Fallback to `gr.Examples()` (#9584) * fic * add changeset * fallback to original examples * add changeset * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Fix `gr.Chatbot` panels layout (#9499) * fix avatar margins * separate component logic out and add message component * fix panel mode and upate chatbot buttons * add changeset * fix type check * fix typecheck * reduce message padding * fix empty message * revert css removal * test * test * Revert "test" This reverts commit40c9e396a1
. * Revert "test" This reverts commit660a6b06ea
. * move message-wrap styes * bubble width + markdown tweak * fix test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Equal height in row false by default (#9591) * changes * add changeset * changes --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix reload mode (#9576) * Ddebuig * Fixing * fix * notebook * add changeset * SSR MODE * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Chatbot autoscroll (#9582) * Auto scroll on the Chatbot component * Scroll down button's design * Parameterize autoscroll * add changeset * Fix test * Fix * Fix the <Video> component to dispatch the load event after the metadata is loaded * add changeset * Add tick * Fix * Fix * Add loadstart and loadeddata and remove load event forwarder from <Video> because <video> doesn't dispatch the load event * Fix <Player> as well * Fix * Add pending_message as the scroll trigger and remove unnecessary tick * Refactoring <Image> * add changeset * Fix * Fix * icon fix * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Dawood <dawoodkhan82@gmail.com> * Only move files to the cache that have a meta key (#9589) * Fix code * add changeset * Code * test * tests * add changeset * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Some more chatbot fixes (#9593) * some fixes * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix favicon in ssr mode (#9592) * Fix favicon * fix * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * SSR e2e + fixes (#9590) * fix tests in ssr mode * fix loading race condition * fix some tests * add ci * cleanup * format * add changeset * clean * test name * broke it, fix * fix? * clean * lint --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Deep equal check with hash (#9580) * check_equal_by_hash * add changeset * changes * change * changes * hash --------- Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Adding new themes to Gradio 5.0 (#9437) * Adding citrus, colorful and headlines themes * add changeset * Fix from running format_backend * Add new themes to theming guide * Rename headlines theme demo file * changes * add changeset * changes * changes * fix name * revert kitchen sink * ocean and docs * changes * add changeset * changes * changes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Ali Abid <aliabid94@gmail.com> * Fix custom component CLI on main/5.0 (#9482) * Add code * add changeset * WIP * add changeset * Working SSR * WIP * Proper ssr build * fix paths * fix * revert .vscode change * format * lint * uncomment * fix --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Fix e2e test bug (#9597) * code * try this out * Fix markdown code copy/check button in gr.Chatbot (#9598) * fix broken copy button * tweak * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * Update `README.md` with 5.0 info and GIFs (#9564) * update gif * format * changes * readme * language * Tweak gr.Dataframe menu UX (#9601) * * show menu on click * only show column options in headers * improve spacing * add changeset * fix type check --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> * chore: update versions (beta) (#9586) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Ensure undo/try shows for final bot message in gr.Chatbot (#9600) * fix undo and retry reactivity * add changeset * tweak * fix ts check * changes * changes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Ali Abid <aliabid94@gmail.com> * chore: update versions (beta) (#9604) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: pngwn <hello@pngwn.io> Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com> Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com> Co-authored-by: aliabid94 <aabid94@gmail.com> Co-authored-by: Ali Abid <aliabid94@gmail.com> Co-authored-by: Yuichiro Tachibana (Tsuchiya) <t.yic.yt@gmail.com> Co-authored-by: Dawood Khan <dawoodkhan82@gmail.com> Co-authored-by: Hannah <hannahblair@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Gradio PR Bot <121576822+gradio-pr-bot@users.noreply.github.com> Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com> Co-authored-by: Tayfun Sen <tayfun.sen@gmail.com> Co-authored-by: Ifeanyi Idiaye <72707830+Ifeanyi55@users.noreply.github.com> Co-authored-by: Charles <charles@huggingface.co> Co-authored-by: Michał Pstrąg <m.pstrag.kontakt@gmail.com> Co-authored-by: Julien Chaumond <julien@huggingface.co> Co-authored-by: Nikita Krasnytskyi <nikita.kras.kyiv@gmail.com> Co-authored-by: Lucain <lucainp@gmail.com> Co-authored-by: Joodith <67360396+Joodith@users.noreply.github.com> Co-authored-by: Col0ring <47329987+Col0ring@users.noreply.github.com> Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@scala.com> Co-authored-by: Mate Valko <3168272+vmatt@users.noreply.github.com> Co-authored-by: Allison <allison@huggingface.co>
1927 lines
64 KiB
Python
1927 lines
64 KiB
Python
import asyncio
|
|
import copy
|
|
import io
|
|
import json
|
|
import os
|
|
import pathlib
|
|
import random
|
|
import sys
|
|
import time
|
|
import uuid
|
|
from concurrent.futures import wait
|
|
from contextlib import contextmanager
|
|
from functools import partial
|
|
from string import capwords
|
|
from unittest.mock import mock_open, patch
|
|
|
|
import gradio_client as grc
|
|
import numpy as np
|
|
import pytest
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
from gradio_client import Client, media_data
|
|
from PIL import Image
|
|
|
|
import gradio as gr
|
|
from gradio import blocks, helpers
|
|
from gradio.data_classes import GradioModel, GradioRootModel
|
|
from gradio.events import SelectData
|
|
from gradio.exceptions import DuplicateBlockError
|
|
from gradio.route_utils import API_PREFIX
|
|
from gradio.utils import assert_configs_are_equivalent_besides_ids, cancel_tasks
|
|
|
|
pytest_plugins = ("pytest_asyncio",)
|
|
|
|
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
|
|
|
|
|
@contextmanager
|
|
def captured_output():
|
|
new_out, new_err = io.StringIO(), io.StringIO()
|
|
old_out, old_err = sys.stdout, sys.stderr
|
|
try:
|
|
sys.stdout, sys.stderr = new_out, new_err
|
|
yield sys.stdout, sys.stderr
|
|
finally:
|
|
sys.stdout, sys.stderr = old_out, old_err
|
|
|
|
|
|
class TestBlocksMethods:
|
|
maxDiff = None
|
|
|
|
def test_set_share_is_false_by_default(self):
|
|
with gr.Blocks() as demo:
|
|
assert not demo.share
|
|
|
|
@patch("gradio.networking.setup_tunnel")
|
|
@patch("gradio.utils.colab_check")
|
|
def test_set_share_in_colab(self, mock_colab_check, mock_setup_tunnel):
|
|
mock_colab_check.return_value = True
|
|
mock_setup_tunnel.return_value = "http://localhost:7860/"
|
|
with gr.Blocks() as demo:
|
|
# self.share is False when instantiating the class
|
|
assert not demo.share
|
|
# share default is True, if share is None in colab and queueing
|
|
demo.launch(prevent_thread_lock=True)
|
|
assert demo.share
|
|
demo.close()
|
|
# share is also true, if share is None in colab with queueing
|
|
demo.queue()
|
|
demo.launch(prevent_thread_lock=True)
|
|
assert demo.share
|
|
demo.close()
|
|
|
|
def test_load_from_config(self):
|
|
fake_url = "https://fake.hf.space"
|
|
|
|
def update(name):
|
|
return f"Welcome to Gradio, {name}!"
|
|
|
|
with gr.Blocks() as demo1:
|
|
inp = gr.Textbox(placeholder="What is your name?")
|
|
out = gr.Textbox()
|
|
|
|
inp.submit(fn=update, inputs=inp, outputs=out, api_name="greet")
|
|
|
|
gr.Image(height=54, width=240)
|
|
|
|
config1 = demo1.get_config_file()
|
|
demo2 = gr.Blocks.from_config(config1, [update], "https://fake.hf.space")
|
|
|
|
for component in config1["components"]:
|
|
component["props"]["proxy_url"] = f"{fake_url}/"
|
|
config2 = demo2.get_config_file()
|
|
assert assert_configs_are_equivalent_besides_ids(config1, config2) # type: ignore
|
|
|
|
def test_partial_fn_in_config(self):
|
|
def greet(name, formatter):
|
|
return formatter(f"Hello {name}!")
|
|
|
|
greet_upper_case = partial(greet, formatter=capwords)
|
|
with gr.Blocks() as demo:
|
|
t = gr.Textbox()
|
|
o = gr.Textbox()
|
|
t.change(greet_upper_case, t, o)
|
|
|
|
assert len(demo.fns) == 1
|
|
assert "fn" in str(demo.fns[0])
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dict_inputs_in_config(self):
|
|
with gr.Blocks() as demo:
|
|
first = gr.Textbox()
|
|
last = gr.Textbox()
|
|
btn = gr.Button()
|
|
greeting = gr.Textbox()
|
|
|
|
def greet(data):
|
|
return f"Hello {data[first]} {data[last]}"
|
|
|
|
btn.click(greet, {first, last}, greeting)
|
|
|
|
result = await demo.process_api(
|
|
inputs=["huggy", "face"], block_fn=0, state=None
|
|
)
|
|
assert result["data"] == ["Hello huggy face"]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_async_function(self):
|
|
async def wait(x):
|
|
await asyncio.sleep(0.01)
|
|
return x
|
|
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
button = gr.Button()
|
|
button.click(wait, [text], [text])
|
|
|
|
start = time.time()
|
|
result = await demo.process_api(inputs=[1], block_fn=0, state=None)
|
|
end = time.time()
|
|
difference = end - start
|
|
assert difference >= 0.01
|
|
assert result
|
|
|
|
@patch("gradio.analytics._do_analytics_request")
|
|
def test_initiated_analytics(self, mock_anlaytics, monkeypatch):
|
|
monkeypatch.setenv("GRADIO_ANALYTICS_ENABLED", "True")
|
|
with gr.Blocks():
|
|
pass
|
|
mock_anlaytics.assert_called_once()
|
|
|
|
@patch("gradio.analytics._do_analytics_request")
|
|
def test_launch_analytics_does_not_error_with_invalid_blocks(
|
|
self, mock_anlaytics, monkeypatch
|
|
):
|
|
monkeypatch.setenv("GRADIO_ANALYTICS_ENABLED", "True")
|
|
with gr.Blocks():
|
|
t1 = gr.Textbox()
|
|
|
|
with gr.Blocks() as demo:
|
|
t2 = gr.Textbox()
|
|
t2.change(lambda x: x, t2, t1)
|
|
|
|
demo.launch(prevent_thread_lock=True)
|
|
mock_anlaytics.assert_called()
|
|
|
|
def test_show_error(self):
|
|
with gr.Blocks() as demo:
|
|
pass
|
|
|
|
assert demo.show_error
|
|
demo.launch(prevent_thread_lock=True)
|
|
assert not demo.show_error
|
|
demo.close()
|
|
demo.launch(show_error=True, prevent_thread_lock=True)
|
|
assert demo.show_error
|
|
demo.close()
|
|
|
|
def test_custom_css(self):
|
|
css = """
|
|
.gr-button {
|
|
color: white;
|
|
border-color: black;
|
|
background: black;
|
|
}
|
|
"""
|
|
css = css * 5 # simulate a long css string
|
|
block = gr.Blocks(css=css)
|
|
|
|
assert block.css == css
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_restart_after_close(self, connect):
|
|
io = gr.Interface(lambda s: s, gr.Textbox(), gr.Textbox()).queue()
|
|
|
|
with connect(io) as client:
|
|
assert client.predict("freddy", api_name="/predict") == "freddy"
|
|
# connect launches the interface which is what we need to test
|
|
with connect(io) as client:
|
|
assert client.predict("Victor", api_name="/predict") == "Victor"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_async_generators(self, connect):
|
|
async def async_iteration(count: int):
|
|
for i in range(count):
|
|
yield i
|
|
await asyncio.sleep(0.2)
|
|
|
|
def iteration(count: int):
|
|
for i in range(count):
|
|
yield i
|
|
time.sleep(0.2)
|
|
|
|
with gr.Blocks() as demo:
|
|
with gr.Row():
|
|
with gr.Column():
|
|
num1 = gr.Number(value=4, precision=0)
|
|
o1 = gr.Number()
|
|
async_iterate = gr.Button(value="Async Iteration")
|
|
async_iterate.click(
|
|
async_iteration,
|
|
num1,
|
|
o1,
|
|
concurrency_limit=2,
|
|
concurrency_id="main",
|
|
)
|
|
with gr.Column():
|
|
num2 = gr.Number(value=4, precision=0)
|
|
o2 = gr.Number()
|
|
iterate = gr.Button(value="Iterate")
|
|
iterate.click(iteration, num2, o2, concurrency_id="main")
|
|
|
|
with connect(demo) as client:
|
|
job_1 = client.submit(3, fn_index=0)
|
|
job_2 = client.submit(4, fn_index=1)
|
|
wait([job_1, job_2])
|
|
|
|
assert job_1.outputs()[-1] == 2
|
|
assert job_2.outputs()[-1] == 3
|
|
|
|
def test_async_generators_interface(self, connect):
|
|
async def async_iteration(count: int):
|
|
for i in range(count):
|
|
yield i
|
|
await asyncio.sleep(0.2)
|
|
|
|
demo = gr.Interface(
|
|
async_iteration, gr.Number(precision=0), gr.Number()
|
|
).queue()
|
|
outputs = []
|
|
with connect(demo) as client:
|
|
for output in client.submit(3, api_name="/predict"):
|
|
outputs.append(output)
|
|
assert outputs == [0, 1, 2]
|
|
|
|
def test_sync_generators(self, connect):
|
|
def generator(string):
|
|
yield from string
|
|
|
|
demo = gr.Interface(generator, "text", "text").queue()
|
|
outputs = []
|
|
with connect(demo) as client:
|
|
for output in client.submit("abc", api_name="/predict"):
|
|
outputs.append(output)
|
|
assert outputs == ["a", "b", "c"]
|
|
demo.queue().launch(prevent_thread_lock=True)
|
|
|
|
def test_varying_output_forms_with_generators(self, connect):
|
|
generations = [
|
|
{"a": 1},
|
|
{"a": 1, "b": [1, 3]},
|
|
{"b": [1, 3, 2]},
|
|
1,
|
|
2,
|
|
3,
|
|
[1, 2, {"x": 4, "y": 6}],
|
|
{"data": [1, 2, {"x": 4, "y": 6}]},
|
|
None,
|
|
1.2,
|
|
]
|
|
|
|
def generator():
|
|
yield from generations
|
|
|
|
def generator_random():
|
|
indices = list(range(len(generations)))
|
|
random.shuffle(indices)
|
|
for i in indices:
|
|
time.sleep(random.random() / 5)
|
|
yield generations[i]
|
|
|
|
with gr.Blocks() as demo:
|
|
btn1 = gr.Button()
|
|
btn2 = gr.Button()
|
|
output_json = gr.JSON()
|
|
btn1.click(generator, None, output_json, api_name="generator")
|
|
btn2.click(generator_random, None, output_json, api_name="generator_random")
|
|
|
|
with connect(demo) as client:
|
|
outputs = []
|
|
for output in client.submit(api_name="/generator"):
|
|
outputs.append(output)
|
|
assert outputs == generations
|
|
|
|
outputs = []
|
|
for output in client.submit(api_name="/generator_random"):
|
|
outputs.append(output)
|
|
for generation in generations:
|
|
assert generation in outputs
|
|
|
|
def test_socket_reuse(self):
|
|
try:
|
|
io = gr.Interface(lambda x: x, gr.Textbox(), gr.Textbox())
|
|
io.launch(server_port=9441, prevent_thread_lock=True)
|
|
io.close()
|
|
io.launch(server_port=9441, prevent_thread_lock=True)
|
|
finally:
|
|
io.close() # type: ignore
|
|
|
|
def test_function_types_documented_in_config(self):
|
|
def continuous_fn():
|
|
return 42
|
|
|
|
def generator_function():
|
|
yield from range(10)
|
|
|
|
with gr.Blocks() as demo:
|
|
gr.Number(value=lambda: 2, every=2)
|
|
meaning_of_life = gr.Number()
|
|
counter = gr.Number()
|
|
generator_btn = gr.Button(value="Generate")
|
|
greeting = gr.Textbox()
|
|
greet_btn = gr.Button(value="Greet")
|
|
|
|
greet_btn.click(lambda: "Hello!", inputs=None, outputs=[greeting])
|
|
generator_btn.click(generator_function, inputs=None, outputs=[counter])
|
|
demo.load(continuous_fn, inputs=None, outputs=[meaning_of_life])
|
|
|
|
assert "dependencies" in demo.config
|
|
dependencies = demo.config["dependencies"]
|
|
assert dependencies[0]["types"] == {
|
|
"generator": False,
|
|
"cancel": False,
|
|
}
|
|
assert dependencies[1]["types"] == {
|
|
"generator": True,
|
|
"cancel": False,
|
|
}
|
|
assert dependencies[2]["types"] == {
|
|
"generator": False,
|
|
"cancel": False,
|
|
}
|
|
assert dependencies[3]["types"] == {
|
|
"generator": False,
|
|
"cancel": False,
|
|
}
|
|
|
|
@patch(
|
|
"gradio.themes.ThemeClass.from_hub",
|
|
side_effect=ValueError("Something went wrong!"),
|
|
)
|
|
def test_use_default_theme_as_fallback(self, mock_from_hub):
|
|
with pytest.warns(
|
|
UserWarning, match="Cannot load freddyaboulton/this-theme-does-not-exist"
|
|
):
|
|
with gr.Blocks(theme="freddyaboulton/this-theme-does-not-exist") as demo:
|
|
assert demo.theme.to_dict() == gr.themes.Default().to_dict()
|
|
|
|
def test_exit_called_at_launch(self):
|
|
with gr.Blocks() as demo:
|
|
gr.Textbox(uuid.uuid4)
|
|
demo.launch(prevent_thread_lock=True)
|
|
config = demo.get_config_file()
|
|
assert "dependencies" in config
|
|
assert len(config["dependencies"]) == 1
|
|
|
|
|
|
class TestTempFile:
|
|
def test_pil_images_hashed(self, connect, gradio_temp_dir):
|
|
images = [
|
|
Image.new("RGB", (512, 512), color) for color in ("red", "green", "blue")
|
|
]
|
|
|
|
def create_images(n_images):
|
|
return random.sample(images, n_images)
|
|
|
|
gallery = gr.Gallery()
|
|
demo = gr.Interface(
|
|
create_images,
|
|
inputs="slider",
|
|
outputs=gallery,
|
|
)
|
|
with connect(demo) as client:
|
|
client.predict(3, api_name="/predict")
|
|
_ = client.predict(3, api_name="/predict")
|
|
# only three files created and in temp directory
|
|
assert len([f for f in gradio_temp_dir.glob("**/*") if f.is_file()]) == 3
|
|
|
|
def test_no_empty_image_files(self, gradio_temp_dir, connect):
|
|
file_dir = pathlib.Path(__file__).parent / "test_files"
|
|
image = grc.handle_file(str(file_dir / "bus.png"))
|
|
|
|
demo = gr.Interface(
|
|
lambda x: x,
|
|
inputs=gr.Image(type="filepath"),
|
|
outputs=gr.Image(),
|
|
)
|
|
with connect(demo) as client:
|
|
_ = client.predict(image, api_name="/predict")
|
|
_ = client.predict(image, api_name="/predict")
|
|
_ = client.predict(image, api_name="/predict")
|
|
# Upload creates a file. image preprocessing creates another one.
|
|
assert len([f for f in gradio_temp_dir.glob("**/*") if f.is_file()]) == 2
|
|
|
|
@pytest.mark.parametrize("component", [gr.UploadButton, gr.File])
|
|
def test_file_component_uploads(self, component, connect, gradio_temp_dir):
|
|
code_file = grc.handle_file(str(pathlib.Path(__file__)))
|
|
demo = gr.Interface(lambda x: x.name, component(), gr.File())
|
|
with connect(demo) as client:
|
|
_ = client.predict(code_file, api_name="/predict")
|
|
_ = client.predict(code_file, api_name="/predict")
|
|
# the upload route hashees the files so we get 1 from there
|
|
# We create two tempfiles (empty) because API says we return
|
|
# preprocess/postprocess will create the same file as the upload route
|
|
# so 1 + 2 = 3
|
|
assert len([f for f in gradio_temp_dir.glob("**/*") if f.is_file()]) == 3
|
|
|
|
def test_no_empty_video_files(self, gradio_temp_dir, connect):
|
|
file_dir = pathlib.Path(pathlib.Path(__file__).parent, "test_files")
|
|
video = grc.handle_file(str(file_dir / "video_sample.mp4"))
|
|
demo = gr.Interface(lambda x: x, gr.Video(), gr.Video())
|
|
with connect(demo) as client:
|
|
_ = client.predict({"video": video}, api_name="/predict")
|
|
_ = client.predict({"video": video}, api_name="/predict")
|
|
# Upload route and postprocessing return the same file
|
|
assert len([f for f in gradio_temp_dir.glob("**/*") if f.is_file()]) == 1
|
|
|
|
def test_no_empty_audio_files(self, gradio_temp_dir, connect):
|
|
file_dir = pathlib.Path(pathlib.Path(__file__).parent, "test_files")
|
|
audio = grc.handle_file(str(file_dir / "audio_sample.wav"))
|
|
|
|
def reverse_audio(audio):
|
|
sr, data = audio
|
|
return (sr, np.flipud(data))
|
|
|
|
demo = gr.Interface(fn=reverse_audio, inputs=gr.Audio(), outputs=gr.Audio())
|
|
with connect(demo) as client:
|
|
_ = client.predict(audio, api_name="/predict")
|
|
_ = client.predict(audio, api_name="/predict")
|
|
# One for upload and one for reversal
|
|
assert len([f for f in gradio_temp_dir.glob("**/*") if f.is_file()]) == 2
|
|
|
|
|
|
class TestComponentsInBlocks:
|
|
def test_slider_random_value_config(self):
|
|
with gr.Blocks() as demo:
|
|
gr.Slider(
|
|
value=11.2,
|
|
minimum=-10.2,
|
|
maximum=15,
|
|
label="Non-random Slider (Static)",
|
|
)
|
|
gr.Slider(
|
|
randomize=True,
|
|
minimum=100,
|
|
maximum=200,
|
|
label="Random Slider (Input 1)",
|
|
)
|
|
gr.Slider(
|
|
randomize=True,
|
|
minimum=10,
|
|
maximum=23.2,
|
|
label="Random Slider (Input 2)",
|
|
)
|
|
for component in demo.blocks.values():
|
|
if isinstance(component, gr.components.Component):
|
|
if "Non-random" in component.label: # type: ignore
|
|
assert not component.load_event_to_attach
|
|
else:
|
|
assert component.load_event_to_attach
|
|
assert "dependencies" in demo.config
|
|
dependencies_on_load = [
|
|
dep["targets"][0][1] == "load" for dep in demo.config["dependencies"]
|
|
]
|
|
assert all(dependencies_on_load)
|
|
assert len(dependencies_on_load) == 2
|
|
|
|
def test_io_components_attach_load_events_when_value_is_fn(self, io_components):
|
|
interface = gr.Interface(
|
|
lambda *args: None,
|
|
inputs=[comp(value=lambda: None, every=1) for comp in io_components],
|
|
outputs=None,
|
|
)
|
|
assert "dependencies" in interface.config
|
|
dependencies_on_load = [
|
|
dep
|
|
for dep in interface.config["dependencies"]
|
|
if "load" in [target[1] for target in dep["targets"]]
|
|
]
|
|
dependencies_on_tick = [
|
|
dep
|
|
for dep in interface.config["dependencies"]
|
|
if "tick" in [target[1] for target in dep["targets"]]
|
|
]
|
|
assert len(dependencies_on_load) == len(io_components)
|
|
assert len(dependencies_on_tick) == len(io_components)
|
|
|
|
def test_get_load_events(self, io_components):
|
|
components = []
|
|
with gr.Blocks() as demo:
|
|
for component in io_components:
|
|
components.append(component(value=lambda: None, every=1))
|
|
assert "dependencies" in demo.config
|
|
assert all(
|
|
comp.load_event in demo.config["dependencies"] for comp in components
|
|
)
|
|
|
|
|
|
class TestBlocksPostprocessing:
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_do_not_filter_none_values_from_updates(self, io_components):
|
|
io_components = [
|
|
c()
|
|
for c in io_components
|
|
if c
|
|
not in [
|
|
gr.State,
|
|
gr.Button,
|
|
gr.ScatterPlot,
|
|
gr.LinePlot,
|
|
gr.BarPlot,
|
|
gr.components.Fallback,
|
|
gr.FileExplorer,
|
|
gr.ParamViewer,
|
|
]
|
|
]
|
|
with gr.Blocks() as demo:
|
|
for component in io_components:
|
|
component.render()
|
|
btn = gr.Button(value="Reset")
|
|
btn.click(
|
|
lambda: [gr.update(value=None) for _ in io_components],
|
|
inputs=[],
|
|
outputs=io_components,
|
|
)
|
|
|
|
output = await demo.postprocess_data(
|
|
demo.fns[0], [gr.update(value=None) for _ in io_components], state=None
|
|
)
|
|
|
|
def process_and_dump(component):
|
|
output = component.postprocess(None)
|
|
if isinstance(output, (GradioModel, GradioRootModel)):
|
|
output = output.model_dump()
|
|
return output
|
|
|
|
assert all(
|
|
o["value"] == process_and_dump(c)
|
|
for o, c in zip(output, io_components, strict=False)
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_does_not_replace_keyword_literal(self):
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
btn = gr.Button(value="Reset")
|
|
btn.click(
|
|
lambda: gr.update(value="NO_VALUE"),
|
|
inputs=[],
|
|
outputs=text,
|
|
)
|
|
|
|
output = await demo.postprocess_data(
|
|
demo.fns[0], gr.update(value="NO_VALUE"), state=None
|
|
)
|
|
assert output[0]["value"] == "NO_VALUE"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_does_not_del_dict_keys_inplace(self):
|
|
with gr.Blocks() as demo:
|
|
im_list = [gr.Image() for i in range(2)]
|
|
|
|
def change_visibility(value):
|
|
return [gr.update(visible=value)] * 2
|
|
|
|
checkbox = gr.Checkbox(value=True, label="Show image")
|
|
checkbox.change(change_visibility, inputs=checkbox, outputs=im_list)
|
|
|
|
output = await demo.postprocess_data(
|
|
demo.fns[0], [gr.update(visible=False)] * 2, state=None
|
|
)
|
|
assert output == [
|
|
{"visible": False, "__type__": "update"},
|
|
{"visible": False, "__type__": "update"},
|
|
]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_returns_correct_output_dict_single_key(self):
|
|
with gr.Blocks() as demo:
|
|
num = gr.Number()
|
|
num2 = gr.Number()
|
|
update = gr.Button(value="update")
|
|
|
|
def update_values(val):
|
|
return {num2: gr.Number(value=42)}
|
|
|
|
update.click(update_values, inputs=[num], outputs=[num2])
|
|
|
|
output = await demo.postprocess_data(
|
|
demo.fns[0], {num2: gr.Number(value=42)}, state=None
|
|
)
|
|
assert output[0]["value"] == 42
|
|
|
|
output = await demo.postprocess_data(demo.fns[0], {num2: 23}, state=None)
|
|
assert output[0] == 23
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_update_dict_without_postprocessing(self):
|
|
def infer(x):
|
|
return media_data.BASE64_IMAGE, gr.update(visible=True)
|
|
|
|
with gr.Blocks() as demo:
|
|
prompt = gr.Textbox()
|
|
image = gr.Image()
|
|
run_button = gr.Button()
|
|
share_button = gr.Button("share", visible=False)
|
|
run_button.click(infer, prompt, [image, share_button], postprocess=False)
|
|
|
|
output = await demo.process_api(0, ["test"], state=None)
|
|
assert output["data"][0] == media_data.BASE64_IMAGE
|
|
assert output["data"][1] == {"__type__": "update", "visible": True}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_update_dict_does_not_postprocess_value_if_postprocessing_false(
|
|
self,
|
|
):
|
|
def infer(x):
|
|
return gr.Image(value=media_data.BASE64_IMAGE)
|
|
|
|
with gr.Blocks() as demo:
|
|
prompt = gr.Textbox()
|
|
image = gr.Image()
|
|
run_button = gr.Button()
|
|
run_button.click(infer, [prompt], [image], postprocess=False)
|
|
|
|
output = await demo.process_api(0, ["test"], state=None)
|
|
assert output["data"][0] == {
|
|
"__type__": "update",
|
|
"value": media_data.BASE64_IMAGE,
|
|
}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_update_interactive(
|
|
self,
|
|
):
|
|
def specific_update():
|
|
return [
|
|
gr.Image(interactive=True),
|
|
gr.Textbox(interactive=True),
|
|
]
|
|
|
|
def generic_update():
|
|
return [gr.update(interactive=True), gr.update(interactive=True)]
|
|
|
|
with gr.Blocks() as demo:
|
|
run = gr.Button(value="Make interactive")
|
|
image = gr.Image()
|
|
textbox = gr.Text()
|
|
run.click(specific_update, None, [image, textbox])
|
|
run.click(generic_update, None, [image, textbox])
|
|
|
|
for fn_index in range(2):
|
|
output = await demo.process_api(fn_index, [], state=None)
|
|
assert output["data"][0] == {
|
|
"__type__": "update",
|
|
"interactive": True,
|
|
}
|
|
assert output["data"][1] == {"__type__": "update", "interactive": True}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_error_raised_if_num_outputs_is_too_low(self):
|
|
with gr.Blocks() as demo:
|
|
textbox1 = gr.Textbox()
|
|
textbox2 = gr.Textbox()
|
|
button = gr.Button()
|
|
button.click(lambda x: x, textbox1, [textbox1, textbox2])
|
|
with pytest.raises(
|
|
ValueError,
|
|
):
|
|
await demo.postprocess_data(demo.fns[0], predictions=["test"], state=None)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_warning_raised_if_num_outputs_is_too_high(self):
|
|
with gr.Blocks() as demo:
|
|
textbox1 = gr.Textbox()
|
|
textbox2 = gr.Textbox()
|
|
button = gr.Button()
|
|
button.click(lambda x: (x, x), textbox1, [textbox1, textbox2])
|
|
with pytest.warns(
|
|
UserWarning,
|
|
):
|
|
await demo.postprocess_data(
|
|
demo.fns[0], predictions=["test", "test2", "test3"], state=None
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_error_raised_if_num_outputs_mismatch_with_function_name(self):
|
|
def infer(x):
|
|
return x
|
|
|
|
with gr.Blocks() as demo:
|
|
textbox1 = gr.Textbox()
|
|
textbox2 = gr.Textbox()
|
|
button = gr.Button()
|
|
button.click(infer, textbox1, [textbox1, textbox2])
|
|
with pytest.raises(
|
|
ValueError,
|
|
):
|
|
await demo.postprocess_data(demo.fns[0], predictions=["test"], state=None)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_error_raised_if_num_outputs_mismatch_single_output(self):
|
|
with gr.Blocks() as demo:
|
|
num1 = gr.Number()
|
|
num2 = gr.Number()
|
|
btn = gr.Button(value="1")
|
|
btn.click(lambda a: a, num1, [num1, num2])
|
|
with pytest.raises(
|
|
ValueError,
|
|
):
|
|
await demo.postprocess_data(demo.fns[0], predictions=[1], state=None)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_error_raised_if_num_outputs_mismatch_tuple_output(self):
|
|
def infer(a, b):
|
|
return a, b
|
|
|
|
with gr.Blocks() as demo:
|
|
num1 = gr.Number()
|
|
num2 = gr.Number()
|
|
num3 = gr.Number()
|
|
btn = gr.Button(value="1")
|
|
btn.click(infer, num1, [num1, num2, num3])
|
|
with pytest.raises(
|
|
ValueError,
|
|
):
|
|
await demo.postprocess_data(demo.fns[0], predictions=[1, 2], state=None)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dataset_is_updated(self):
|
|
def update(value):
|
|
return value, gr.Dataset(samples=[["New A"], ["New B"]])
|
|
|
|
with gr.Blocks() as demo:
|
|
with gr.Row():
|
|
textbox = gr.Textbox()
|
|
dataset = gr.Dataset(
|
|
components=["text"], samples=[["Original"]], label="Saved Prompts"
|
|
)
|
|
dataset.click(update, inputs=[dataset], outputs=[textbox, dataset])
|
|
app, _, _ = demo.launch(prevent_thread_lock=True)
|
|
|
|
client = TestClient(app)
|
|
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [0], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert "Original" in session_1.json()["data"][0]
|
|
session_2 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [0], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert "New" in session_2.json()["data"][0]
|
|
|
|
|
|
class TestStateHolder:
|
|
@pytest.mark.asyncio
|
|
async def test_state_stored_up_to_capacity(self):
|
|
with gr.Blocks() as demo:
|
|
num = gr.Number()
|
|
state = gr.State(value=0)
|
|
|
|
def run(x, s):
|
|
return s, s + 1
|
|
|
|
num.submit(
|
|
run,
|
|
inputs=[num, state],
|
|
outputs=[num, state],
|
|
)
|
|
app, _, _ = demo.launch(prevent_thread_lock=True, state_session_capacity=2)
|
|
client = TestClient(app)
|
|
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert session_1.json()["data"][0] == 0
|
|
session_2 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "2", "fn_index": 0},
|
|
)
|
|
assert session_2.json()["data"][0] == 0
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert session_1.json()["data"][0] == 1
|
|
session_2 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "2", "fn_index": 0},
|
|
)
|
|
assert session_2.json()["data"][0] == 1
|
|
session_3 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "3", "fn_index": 0},
|
|
)
|
|
assert session_3.json()["data"][0] == 0
|
|
session_2 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "2", "fn_index": 0},
|
|
)
|
|
assert session_2.json()["data"][0] == 2
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [1, None], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert (
|
|
session_1.json()["data"][0] == 0
|
|
) # state was lost for session 1 when session 3 was added, since state_session_capacity=2
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_updates_stored_up_to_capacity(self):
|
|
with gr.Blocks() as demo:
|
|
min = gr.Number()
|
|
num = gr.Number()
|
|
|
|
def run(min, num):
|
|
return min, gr.Number(value=num, minimum=min)
|
|
|
|
num.submit(
|
|
run,
|
|
inputs=[min, num],
|
|
outputs=[min, num],
|
|
)
|
|
app, _, _ = demo.launch(prevent_thread_lock=True, state_session_capacity=2)
|
|
client = TestClient(app)
|
|
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [5, 5], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert session_1.json()["data"][0] == 5
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [2, 2], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert "error" in session_1.json() # error because min is 5 and num is 2
|
|
session_2 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [5, 5], "session_hash": "2", "fn_index": 0},
|
|
)
|
|
assert session_2.json()["data"][0] == 5
|
|
session_3 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [5, 5], "session_hash": "3", "fn_index": 0},
|
|
)
|
|
assert session_3.json()["data"][0] == 5
|
|
session_1 = client.post(
|
|
f"{API_PREFIX}/api/predict/",
|
|
json={"data": [2, 2], "session_hash": "1", "fn_index": 0},
|
|
)
|
|
assert (
|
|
"error" not in session_1.json()
|
|
) # no error because sesssion 1 block config was lost when session 3 was added
|
|
|
|
def test_state_holder_is_used_in_postprocess(self, connect):
|
|
with gr.Blocks() as demo:
|
|
dropdown = gr.Dropdown(label="list", choices=["Choice 1"], interactive=True)
|
|
button = gr.Button("Get dropdown value")
|
|
button2 = gr.Button("Convert dropdown to multiselect")
|
|
button.click(
|
|
lambda x: x, inputs=dropdown, outputs=dropdown, api_name="predict"
|
|
)
|
|
button2.click(
|
|
lambda: gr.Dropdown(multiselect=True),
|
|
outputs=dropdown,
|
|
api_name="set_multiselect",
|
|
)
|
|
|
|
client: Client
|
|
with connect(demo) as client:
|
|
assert client.predict("Choice 1", api_name="/predict") == "Choice 1"
|
|
client.predict(api_name="/set_multiselect")
|
|
assert client.predict("Choice 1", api_name="/predict") == ["Choice 1"]
|
|
|
|
|
|
class TestCallFunction:
|
|
@pytest.mark.asyncio
|
|
async def test_call_regular_function(self):
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
btn = gr.Button()
|
|
btn.click(
|
|
lambda x: f"Hello, {x}",
|
|
inputs=text,
|
|
outputs=text,
|
|
)
|
|
|
|
output = await demo.call_function(0, ["World"])
|
|
assert output["prediction"] == "Hello, World"
|
|
output = demo("World")
|
|
assert output == "Hello, World"
|
|
|
|
output = await demo.call_function(0, ["Abubakar"])
|
|
assert output["prediction"] == "Hello, Abubakar"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_call_multiple_functions(self):
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
text2 = gr.Textbox()
|
|
btn = gr.Button()
|
|
btn.click(
|
|
lambda x: f"Hello, {x}",
|
|
inputs=text,
|
|
outputs=text,
|
|
)
|
|
text.change(
|
|
lambda x: f"Hi, {x}",
|
|
inputs=text,
|
|
outputs=text2,
|
|
)
|
|
|
|
output = await demo.call_function(0, ["World"])
|
|
assert output["prediction"] == "Hello, World"
|
|
output = demo("World")
|
|
assert output == "Hello, World"
|
|
|
|
output = await demo.call_function(1, ["World"])
|
|
assert output["prediction"] == "Hi, World"
|
|
output = demo("World", fn_index=1) # fn_index must be a keyword argument
|
|
assert output == "Hi, World"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_call_decorated_functions(self):
|
|
with gr.Blocks() as demo:
|
|
name = gr.Textbox(value="Abubakar")
|
|
output = gr.Textbox(label="Output Box")
|
|
|
|
@name.submit(inputs=name, outputs=output)
|
|
@demo.load(inputs=name, outputs=output)
|
|
def test(x):
|
|
return "Hello " + x
|
|
|
|
output = await demo.call_function(0, ["Adam"])
|
|
assert output["prediction"] == "Hello Adam"
|
|
output = await demo.call_function(1, ["Adam"])
|
|
assert output["prediction"] == "Hello Adam"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_call_generator(self):
|
|
def generator(x):
|
|
yield from range(x)
|
|
|
|
with gr.Blocks() as demo:
|
|
inp = gr.Number()
|
|
out = gr.Number()
|
|
btn = gr.Button()
|
|
btn.click(
|
|
generator,
|
|
inputs=inp,
|
|
outputs=out,
|
|
)
|
|
|
|
demo.queue()
|
|
assert demo.config["enable_queue"]
|
|
|
|
output = await demo.call_function(0, [3])
|
|
assert output["prediction"] == 0
|
|
output = await demo.call_function(0, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == 1
|
|
output = await demo.call_function(0, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == 2
|
|
output = await demo.call_function(0, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == gr.components._Keywords.FINISHED_ITERATING
|
|
assert output["iterator"] is None
|
|
output = await demo.call_function(0, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == 0
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_call_both_generator_and_function(self):
|
|
def generator(x):
|
|
for i in range(x):
|
|
yield i, x
|
|
|
|
with gr.Blocks() as demo:
|
|
inp = gr.Number()
|
|
out1 = gr.Number()
|
|
out2 = gr.Number()
|
|
btn = gr.Button()
|
|
inp.change(lambda x: x + x, inp, out1)
|
|
btn.click(
|
|
generator,
|
|
inputs=inp,
|
|
outputs=[out1, out2],
|
|
)
|
|
|
|
demo.queue()
|
|
|
|
output = await demo.call_function(0, [2])
|
|
assert output["prediction"] == 4
|
|
output = await demo.call_function(0, [-1])
|
|
assert output["prediction"] == -2
|
|
|
|
output = await demo.call_function(1, [3])
|
|
assert output["prediction"] == (0, 3)
|
|
output = await demo.call_function(1, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == (1, 3)
|
|
output = await demo.call_function(1, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == (2, 3)
|
|
output = await demo.call_function(1, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == (gr.components._Keywords.FINISHED_ITERATING,) * 2
|
|
assert output["iterator"] is None
|
|
output = await demo.call_function(1, [3], iterator=output["iterator"])
|
|
assert output["prediction"] == (0, 3)
|
|
|
|
|
|
class TestBatchProcessing:
|
|
def test_raise_exception_if_batching_an_event_thats_not_queued(self):
|
|
def trim(words, lens):
|
|
trimmed_words = [
|
|
word[: int(length)] for word, length in zip(words, lens, strict=False)
|
|
]
|
|
return [trimmed_words]
|
|
|
|
msg = "In order to use batching, the queue must be enabled."
|
|
|
|
with pytest.raises(ValueError, match=msg):
|
|
with gr.Blocks() as demo:
|
|
with gr.Row():
|
|
word = gr.Textbox(label="word")
|
|
leng = gr.Number(label="leng")
|
|
output = gr.Textbox(label="Output")
|
|
with gr.Row():
|
|
run = gr.Button()
|
|
|
|
run.click(
|
|
trim,
|
|
[word, leng],
|
|
output,
|
|
batch=True,
|
|
max_batch_size=16,
|
|
queue=False,
|
|
)
|
|
demo.queue()
|
|
demo.launch(prevent_thread_lock=True)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_call_regular_function(self):
|
|
def batch_fn(x):
|
|
results = []
|
|
for word in x:
|
|
results.append(f"Hello {word}")
|
|
return (results,)
|
|
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
btn = gr.Button()
|
|
btn.click(batch_fn, inputs=text, outputs=text, batch=True)
|
|
|
|
output = await demo.call_function(0, [["Adam", "Yahya"]])
|
|
assert output["prediction"][0] == ["Hello Adam", "Hello Yahya"]
|
|
output = demo("Abubakar")
|
|
assert output == "Hello Abubakar"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_functions_multiple_parameters(self):
|
|
def regular_fn(word1, word2):
|
|
return len(word1) > len(word2)
|
|
|
|
def batch_fn(words, lengths):
|
|
comparisons = []
|
|
trim_words = []
|
|
for word, length in zip(words, lengths, strict=False):
|
|
trim_words.append(word[:length])
|
|
comparisons.append(len(word) > length)
|
|
return trim_words, comparisons
|
|
|
|
with gr.Blocks() as demo:
|
|
text1 = gr.Textbox()
|
|
text2 = gr.Textbox()
|
|
leng = gr.Number(precision=0)
|
|
bigger = gr.Checkbox()
|
|
btn1 = gr.Button("Check")
|
|
btn2 = gr.Button("Trim")
|
|
btn1.click(regular_fn, inputs=[text1, text2], outputs=bigger)
|
|
btn2.click(
|
|
batch_fn,
|
|
inputs=[text1, leng],
|
|
outputs=[text1, bigger],
|
|
batch=True,
|
|
)
|
|
|
|
output = await demo.call_function(0, ["Adam", "Yahya"])
|
|
assert output["prediction"] is False
|
|
output = demo("Abubakar", "Abid")
|
|
assert output
|
|
|
|
output = await demo.call_function(1, [["Adam", "Mary"], [3, 5]])
|
|
assert output["prediction"] == (
|
|
["Ada", "Mary"],
|
|
[True, False],
|
|
)
|
|
output = demo("Abubakar", 3, fn_index=1)
|
|
assert output == ["Abu", True]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_invalid_batch_generator(self):
|
|
with pytest.raises(ValueError):
|
|
|
|
def batch_fn(x):
|
|
results = []
|
|
for word in x:
|
|
results.append(f"Hello {word}")
|
|
yield (results,)
|
|
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
btn = gr.Button()
|
|
btn.click(batch_fn, inputs=text, outputs=text, batch=True)
|
|
|
|
await demo.process_api(0, [["Adam", "Yahya"]], state=None)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_exceeds_max_batch_size(self):
|
|
with pytest.raises(ValueError):
|
|
|
|
def batch_fn(x):
|
|
results = []
|
|
for word in x:
|
|
results.append(f"Hello {word}")
|
|
return (results,)
|
|
|
|
with gr.Blocks() as demo:
|
|
text = gr.Textbox()
|
|
btn = gr.Button()
|
|
btn.click(
|
|
batch_fn, inputs=text, outputs=text, batch=True, max_batch_size=2
|
|
)
|
|
|
|
await demo.process_api(0, [["A", "B", "C"]], state=None)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_unequal_batch_sizes(self):
|
|
with pytest.raises(ValueError):
|
|
|
|
def batch_fn(x, y):
|
|
results = []
|
|
for word1, word2 in zip(x, y, strict=False):
|
|
results.append(f"Hello {word1}{word2}")
|
|
return (results,)
|
|
|
|
with gr.Blocks() as demo:
|
|
t1 = gr.Textbox()
|
|
t2 = gr.Textbox()
|
|
btn = gr.Button()
|
|
btn.click(batch_fn, inputs=[t1, t2], outputs=t1, batch=True)
|
|
|
|
await demo.process_api(0, [["A", "B", "C"], ["D", "E"]], state=None)
|
|
|
|
|
|
class TestUpdate:
|
|
@pytest.mark.asyncio
|
|
async def test_accordion_update(self):
|
|
with gr.Blocks() as demo:
|
|
with gr.Accordion(label="Open for greeting", open=False) as accordion:
|
|
gr.Textbox("Hello!")
|
|
open_btn = gr.Button("Open Accordion")
|
|
close_btn = gr.Button("Close Accordion")
|
|
open_btn.click(
|
|
lambda: gr.Accordion(open=True, label="Open Accordion"),
|
|
inputs=None,
|
|
outputs=[accordion],
|
|
)
|
|
close_btn.click(
|
|
lambda: gr.Accordion(open=False, label="Closed Accordion"),
|
|
inputs=None,
|
|
outputs=[accordion],
|
|
)
|
|
result = await demo.process_api(
|
|
block_fn=0, inputs=[None], request=None, state=None
|
|
)
|
|
assert result["data"][0] == {
|
|
"open": True,
|
|
"label": "Open Accordion",
|
|
"__type__": "update",
|
|
}
|
|
result = await demo.process_api(
|
|
block_fn=1, inputs=[None], request=None, state=None
|
|
)
|
|
assert result["data"][0] == {
|
|
"open": False,
|
|
"label": "Closed Accordion",
|
|
"__type__": "update",
|
|
}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_root_path():
|
|
image_file = pathlib.Path(__file__).parent / "test_files" / "bus.png"
|
|
demo = gr.Interface(lambda x: image_file, "textbox", "image")
|
|
result = await demo.process_api(block_fn=0, inputs=[""], request=None, state=None)
|
|
result_url = result["data"][0]["url"]
|
|
assert result_url.startswith(f"{API_PREFIX}/file=")
|
|
assert result_url.endswith("bus.png")
|
|
|
|
result = await demo.process_api(
|
|
block_fn=0, inputs=[""], request=None, state=None, root_path="abidlabs.hf.space"
|
|
)
|
|
result_url = result["data"][0]["url"]
|
|
assert result_url.startswith(f"abidlabs.hf.space{API_PREFIX}/file=")
|
|
assert result_url.endswith("bus.png")
|
|
|
|
|
|
class TestRender:
|
|
def test_duplicate_error(self):
|
|
with pytest.raises(DuplicateBlockError):
|
|
t = gr.Textbox()
|
|
with gr.Blocks():
|
|
t.render()
|
|
gr.Number()
|
|
t.render()
|
|
|
|
with pytest.raises(DuplicateBlockError):
|
|
with gr.Blocks():
|
|
t = gr.Textbox()
|
|
t.render()
|
|
|
|
with pytest.raises(DuplicateBlockError):
|
|
io = gr.Interface(lambda x: x, gr.Textbox(), gr.Textbox())
|
|
with gr.Blocks():
|
|
io.render()
|
|
io.render()
|
|
|
|
with pytest.raises(DuplicateBlockError):
|
|
t = gr.Textbox()
|
|
io = gr.Interface(lambda x: x, t, gr.Textbox())
|
|
with gr.Blocks():
|
|
io.render()
|
|
t.render()
|
|
|
|
def test_no_error(self):
|
|
t = gr.Textbox()
|
|
t2 = gr.Textbox()
|
|
with gr.Blocks():
|
|
t.render()
|
|
t3 = t2.render()
|
|
assert t2 == t3
|
|
|
|
t = gr.Textbox()
|
|
io = gr.Interface(lambda x: x, t, gr.Textbox())
|
|
with gr.Blocks():
|
|
io.render()
|
|
gr.Textbox()
|
|
|
|
io = gr.Interface(lambda x: x, gr.Textbox(), gr.Textbox())
|
|
io2 = gr.Interface(lambda x: x, gr.Textbox(), gr.Textbox())
|
|
with gr.Blocks():
|
|
io.render()
|
|
io3 = io2.render()
|
|
assert io2 == io3
|
|
|
|
def test_is_rendered(self):
|
|
t = gr.Textbox()
|
|
with gr.Blocks():
|
|
pass
|
|
assert not t.is_rendered
|
|
|
|
t = gr.Textbox()
|
|
with gr.Blocks():
|
|
t.render()
|
|
assert t.is_rendered
|
|
|
|
t = gr.Textbox()
|
|
with gr.Blocks():
|
|
t.render()
|
|
t.unrender()
|
|
assert not t.is_rendered
|
|
|
|
with gr.Blocks():
|
|
t = gr.Textbox()
|
|
assert t.is_rendered
|
|
|
|
with gr.Blocks():
|
|
t = gr.Textbox()
|
|
with gr.Blocks():
|
|
pass
|
|
assert t.is_rendered
|
|
|
|
t = gr.Textbox()
|
|
gr.Interface(lambda x: x, "textbox", t)
|
|
assert t.is_rendered
|
|
|
|
def test_no_error_if_state_rendered_multiple_times(self):
|
|
state = gr.State("")
|
|
gr.TabbedInterface(
|
|
[
|
|
gr.Interface(
|
|
lambda _, x: (x, "I don't know"),
|
|
inputs=[state, gr.Textbox()],
|
|
outputs=[state, gr.Textbox()],
|
|
),
|
|
gr.Interface(
|
|
lambda s: (s, f"User question: {s}"),
|
|
inputs=[state],
|
|
outputs=[state, gr.Textbox(interactive=False)],
|
|
),
|
|
],
|
|
["Ask question", "Show question"],
|
|
)
|
|
|
|
|
|
class TestCancel:
|
|
@pytest.mark.asyncio
|
|
async def test_cancel_function(self, capsys):
|
|
async def long_job():
|
|
await asyncio.sleep(10)
|
|
print("HELLO FROM LONG JOB")
|
|
|
|
with gr.Blocks():
|
|
button = gr.Button(value="Start")
|
|
click = button.click(long_job, None, None)
|
|
cancel = gr.Button(value="Cancel")
|
|
cancel.click(None, None, None, cancels=[click])
|
|
|
|
task = asyncio.create_task(long_job())
|
|
task.set_name("foo_0<gradio-sep>event")
|
|
# If cancel_fun didn't cancel long_job the message would be printed to the console
|
|
# The test would also take 10 seconds
|
|
await asyncio.gather(task, cancel_tasks({"foo_0"}), return_exceptions=True)
|
|
captured = capsys.readouterr()
|
|
assert "HELLO FROM LONG JOB" not in captured.out
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cancel_function_with_multiple_blocks(self, capsys):
|
|
async def long_job():
|
|
await asyncio.sleep(10)
|
|
print("HELLO FROM LONG JOB")
|
|
|
|
with gr.Blocks() as demo1:
|
|
textbox = gr.Textbox()
|
|
button1 = gr.Button(value="Start")
|
|
button1.click(lambda x: x, textbox, textbox)
|
|
with gr.Blocks() as demo2:
|
|
button2 = gr.Button(value="Start")
|
|
click = button2.click(long_job, None, None)
|
|
cancel = gr.Button(value="Cancel")
|
|
cancel.click(None, None, None, cancels=[click])
|
|
|
|
with gr.Blocks():
|
|
with gr.Tab("Demo 1"):
|
|
demo1.render()
|
|
with gr.Tab("Demo 2"):
|
|
demo2.render()
|
|
|
|
task = asyncio.create_task(long_job())
|
|
task.set_name("foo_1<gradio-sep>event")
|
|
await asyncio.gather(task, cancel_tasks({"foo_1"}), return_exceptions=True)
|
|
captured = capsys.readouterr()
|
|
assert "HELLO FROM LONG JOB" not in captured.out
|
|
|
|
def test_raise_exception_if_cancelling_an_event_thats_not_queued(self):
|
|
def iteration(a):
|
|
yield a
|
|
|
|
msg = "Queue needs to be enabled!"
|
|
|
|
with pytest.raises(ValueError, match=msg):
|
|
with gr.Blocks() as demo:
|
|
button = gr.Button(value="Predict")
|
|
click = button.click(None, None, None)
|
|
cancel = gr.Button(value="Cancel")
|
|
cancel.click(None, None, None, cancels=[click], queue=False)
|
|
demo.launch(prevent_thread_lock=True)
|
|
|
|
with pytest.raises(ValueError, match=msg):
|
|
with gr.Blocks() as demo:
|
|
button = gr.Button(value="Predict")
|
|
click = button.click(None, None, None, queue=False)
|
|
cancel = gr.Button(value="Cancel")
|
|
cancel.click(None, None, None, cancels=[click])
|
|
demo.queue().launch(prevent_thread_lock=True)
|
|
|
|
|
|
class TestGetAPIInfo:
|
|
def test_many_endpoints(self):
|
|
with gr.Blocks() as demo:
|
|
t1 = gr.Textbox()
|
|
t2 = gr.Textbox()
|
|
t3 = gr.Textbox()
|
|
t4 = gr.Textbox()
|
|
t5 = gr.Textbox()
|
|
t1.change(lambda x: x, t1, t2, api_name="change1")
|
|
t2.change(lambda x: x, t2, t3, api_name="change2")
|
|
t3.change(lambda x: x, t3, t4, api_name=False)
|
|
t4.change(lambda x: x, t4, t5, api_name=False)
|
|
|
|
api_info = demo.get_api_info()
|
|
assert api_info
|
|
assert len(api_info["named_endpoints"]) == 2
|
|
assert len(api_info["unnamed_endpoints"]) == 0
|
|
|
|
def test_no_endpoints(self):
|
|
with gr.Blocks() as demo:
|
|
t1 = gr.Textbox()
|
|
t2 = gr.Textbox()
|
|
t1.change(lambda x: x, t1, t2, api_name=False)
|
|
|
|
api_info = demo.get_api_info()
|
|
assert api_info
|
|
assert len(api_info["named_endpoints"]) == 0
|
|
assert len(api_info["unnamed_endpoints"]) == 0
|
|
|
|
|
|
class TestAddRequests:
|
|
def test_no_type_hints(self):
|
|
def moo(a, b):
|
|
return a + b
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs
|
|
|
|
boo = partial(moo, a=1)
|
|
inputs = [2]
|
|
inputs_ = helpers.special_args(boo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs
|
|
|
|
def test_no_type_hints_with_request(self):
|
|
def moo(a: str, b: int):
|
|
return a + str(b)
|
|
|
|
inputs = ["abc", 2]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs
|
|
|
|
boo = partial(moo, a="def")
|
|
inputs = [2]
|
|
inputs_ = helpers.special_args(boo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs
|
|
|
|
def test_type_hints_with_request(self):
|
|
def moo2(a: str, b: gr.Request):
|
|
return a
|
|
|
|
inputs = ["abc"]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo2, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs + [request]
|
|
|
|
def moo(a: gr.Request, b, c: int):
|
|
return c
|
|
|
|
inputs = ["abc", 5]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == [request] + inputs
|
|
|
|
def test_type_hints_with_multiple_requests(self):
|
|
def moo2(a: str, b: gr.Request, c: gr.Request):
|
|
return a
|
|
|
|
inputs = ["abc"]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo2, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs + [request, request]
|
|
|
|
def moo(a: gr.Request, b, c: int, d: gr.Request):
|
|
return c
|
|
|
|
inputs = ["abc", 5]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == [request] + inputs + [request]
|
|
|
|
def test_default_args(self):
|
|
def moo(a, b, c=42):
|
|
return a + b + c
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs + [42]
|
|
|
|
inputs = [1, 2, 24]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs
|
|
|
|
def test_default_args_with_progress(self):
|
|
pr = gr.Progress()
|
|
|
|
def moo2(a, b, c=42, pr=pr):
|
|
return a + b + c
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_, progress_index, _ = helpers.special_args(
|
|
moo2, copy.deepcopy(inputs), request
|
|
)
|
|
assert inputs_ == inputs + [42, pr]
|
|
assert progress_index == 3
|
|
|
|
inputs = [1, 2, 24]
|
|
request = gr.Request()
|
|
inputs_, progress_index, _ = helpers.special_args(
|
|
moo2, copy.deepcopy(inputs), request
|
|
)
|
|
assert inputs_ == inputs + [pr]
|
|
assert progress_index == 3
|
|
|
|
def moo(a, b, pr=pr, c=42):
|
|
return a + b + c
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_, progress_index, _ = helpers.special_args(
|
|
moo, copy.deepcopy(inputs), request
|
|
)
|
|
assert inputs_ == inputs + [pr, 42]
|
|
assert progress_index == 2
|
|
|
|
def test_default_args_with_request(self):
|
|
pr = gr.Progress()
|
|
|
|
def moo2(a, b, req: gr.Request, c=42):
|
|
return a + b + c
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo2, copy.deepcopy(inputs), request)[0]
|
|
assert inputs_ == inputs + [request, 42]
|
|
|
|
def moo(a, b, req: gr.Request, c=42, pr=pr):
|
|
return a + b + c
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_, progress_index, _ = helpers.special_args(
|
|
moo, copy.deepcopy(inputs), request
|
|
)
|
|
assert inputs_ == inputs + [request, 42, pr]
|
|
assert progress_index == 4
|
|
|
|
def test_default_args_with_event_data(self):
|
|
pr = gr.Progress()
|
|
target = gr.Textbox()
|
|
|
|
def moo(a, b, ed: SelectData, c=42):
|
|
return a + b + c
|
|
|
|
event_data = SelectData(target=target, data={"index": 24, "value": "foo"})
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_ = helpers.special_args(moo, copy.deepcopy(inputs), request, event_data)[
|
|
0
|
|
]
|
|
assert len(inputs_) == 4
|
|
new_event_data = inputs_[2]
|
|
assert inputs_ == inputs + [new_event_data, 42]
|
|
assert isinstance(new_event_data, SelectData)
|
|
assert new_event_data.target == target
|
|
assert new_event_data.index == 24
|
|
assert new_event_data.value == "foo"
|
|
|
|
def moo2(a, b, ed: SelectData, c=42, pr=pr):
|
|
return a + b + c
|
|
|
|
inputs = [1, 2]
|
|
request = gr.Request()
|
|
inputs_, progress_index, _ = helpers.special_args(
|
|
moo2, copy.deepcopy(inputs), request, event_data
|
|
)
|
|
assert len(inputs_) == 5
|
|
new_event_data = inputs_[2]
|
|
assert inputs_ == inputs + [new_event_data, 42, pr]
|
|
assert progress_index == 4
|
|
assert isinstance(new_event_data, SelectData)
|
|
assert new_event_data.target == target
|
|
assert new_event_data.index == 24
|
|
assert new_event_data.value == "foo"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_queue_when_using_auth():
|
|
sleep_time = 1
|
|
|
|
async def say_hello(name):
|
|
await asyncio.sleep(sleep_time)
|
|
return f"Hello {name}!"
|
|
|
|
with gr.Blocks() as demo:
|
|
_input = gr.Textbox()
|
|
_output = gr.Textbox()
|
|
button = gr.Button()
|
|
button.click(say_hello, _input, _output)
|
|
demo.queue()
|
|
app, _, _ = demo.launch(auth=("abc", "123"), prevent_thread_lock=True)
|
|
|
|
with pytest.raises(ValueError):
|
|
grc.Client(f"http://localhost:{demo.server_port}")
|
|
|
|
client = grc.Client(f"http://localhost:{demo.server_port}", auth=("abc", "123"))
|
|
jobs = []
|
|
for i in range(3):
|
|
jobs.append(client.submit(f"World {i}", fn_index=0))
|
|
|
|
for i, job in enumerate(jobs):
|
|
assert job.result() == f"Hello World {i}!"
|
|
|
|
|
|
def test_temp_file_sets_get_extended():
|
|
test_file_dir = pathlib.Path(pathlib.Path(__file__).parent, "test_files")
|
|
|
|
with gr.Blocks() as demo1:
|
|
gr.Video(str(test_file_dir / "video_sample.mp4"))
|
|
|
|
with gr.Blocks() as demo2:
|
|
gr.Audio(str(test_file_dir / "audio_sample.wav"))
|
|
|
|
with gr.Blocks() as demo3:
|
|
demo1.render()
|
|
demo2.render()
|
|
# The upload_set is empty so we remove it from the check
|
|
demo_3_no_empty = [s for s in demo3.temp_file_sets if len(s)]
|
|
demo_1_and_2_no_empty = [
|
|
s for s in demo1.temp_file_sets + demo2.temp_file_sets if len(s)
|
|
]
|
|
assert demo_3_no_empty == demo_1_and_2_no_empty
|
|
|
|
|
|
def test_recover_kwargs():
|
|
audio = gr.Audio(format="wav", autoplay=True)
|
|
props = audio.recover_kwargs(
|
|
{"format": "wav", "value": "foo.wav", "autoplay": False, "foo": "bar"}
|
|
)
|
|
assert props == {"format": "wav", "value": "foo.wav", "autoplay": False}
|
|
props = audio.recover_kwargs(
|
|
{"format": "wav", "value": "foo.wav", "autoplay": False, "foo": "bar"},
|
|
["value"],
|
|
)
|
|
assert props == {"format": "wav", "autoplay": False}
|
|
|
|
|
|
def test_postprocess_update_dict():
|
|
block = gr.Textbox()
|
|
update_dict = {"value": 2.0, "visible": True, "invalid_arg": "hello"}
|
|
assert blocks.postprocess_update_dict(block, update_dict, True) == {
|
|
"__type__": "update",
|
|
"value": "2.0",
|
|
"visible": True,
|
|
}
|
|
|
|
block = gr.Textbox(lines=10)
|
|
update_dict = {"value": 2.0, "lines": 10}
|
|
assert blocks.postprocess_update_dict(block, update_dict, False) == {
|
|
"__type__": "update",
|
|
"value": 2.0,
|
|
"lines": 10,
|
|
}
|
|
|
|
block = gr.Dropdown(choices=["New Country A", "New Country B"])
|
|
update_dict = {
|
|
"value": "New Country A",
|
|
"choices": ["New Country A", "New Country B"],
|
|
}
|
|
assert blocks.postprocess_update_dict(block, update_dict, False) == {
|
|
"__type__": "update",
|
|
"value": "New Country A",
|
|
"choices": [
|
|
("New Country A", "New Country A"),
|
|
("New Country B", "New Country B"),
|
|
],
|
|
}
|
|
|
|
|
|
def test_async_iterator_update_with_new_component(connect):
|
|
async def get_number_stream():
|
|
for i in range(10):
|
|
yield gr.Number(value=i, label="Number (updates every second)")
|
|
|
|
await asyncio.sleep(0.1)
|
|
|
|
demo = gr.Interface(fn=get_number_stream, inputs=None, outputs=["number"])
|
|
demo.queue()
|
|
|
|
with connect(demo) as client:
|
|
job = client.submit(api_name="/predict")
|
|
job.result()
|
|
assert [r["value"] for r in job.outputs()] == list(range(10))
|
|
|
|
|
|
def test_emptry_string_api_name_gets_set_as_fn_name():
|
|
def test_fn(x):
|
|
return x
|
|
|
|
with gr.Blocks() as demo:
|
|
t1 = gr.Textbox()
|
|
t2 = gr.Textbox()
|
|
t1.change(test_fn, t1, t2, api_name="")
|
|
|
|
assert demo.fns[0].api_name == "test_fn"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_blocks_postprocessing_with_copies_of_component_instance():
|
|
# Test for: https://github.com/gradio-app/gradio/issues/6608
|
|
with gr.Blocks() as demo:
|
|
chatbot = gr.Chatbot()
|
|
chatbot2 = gr.Chatbot()
|
|
chatbot3 = gr.Chatbot()
|
|
clear = gr.Button("Clear")
|
|
|
|
def clear_func():
|
|
return tuple([gr.Chatbot(value=[])] * 3)
|
|
|
|
clear.click(
|
|
fn=clear_func, outputs=[chatbot, chatbot2, chatbot3], api_name="clear"
|
|
)
|
|
|
|
output = await demo.postprocess_data(
|
|
demo.fns[0], [gr.Chatbot(value=[])] * 3, None
|
|
)
|
|
assert output == [{"value": [], "__type__": "update"}] * 3
|
|
|
|
|
|
def test_static_files_single_app(connect, gradio_temp_dir):
|
|
gr.set_static_paths(
|
|
paths=["test/test_files/cheetah1.jpg", "test/test_files/bus.png"]
|
|
)
|
|
demo = gr.Interface(
|
|
lambda s: s.rotate(45),
|
|
gr.Image(value="test/test_files/cheetah1.jpg", type="pil"),
|
|
gr.Image(),
|
|
examples=["test/test_files/bus.png"],
|
|
)
|
|
|
|
# Nothing got saved to cache
|
|
assert len(list(gradio_temp_dir.glob("**/*.*"))) == 0
|
|
|
|
with connect(demo) as client:
|
|
client.predict(grc.handle_file("test/test_files/bus.png"))
|
|
|
|
# Input/Output got saved to cache
|
|
assert len(list(gradio_temp_dir.glob("**/*.*"))) == 2
|
|
|
|
|
|
def test_static_files_multiple_apps(gradio_temp_dir):
|
|
gr.set_static_paths(paths=["test/test_files/cheetah1.jpg"])
|
|
demo = gr.Interface(
|
|
lambda s: s.rotate(45),
|
|
gr.Image(value="test/test_files/cheetah1.jpg"),
|
|
gr.Image(),
|
|
)
|
|
|
|
gr.set_static_paths(paths=["test/test_files/images"])
|
|
demo_2 = gr.Interface(
|
|
lambda s: s.rotate(45),
|
|
gr.Image(value="test/test_files/images/bus.png"),
|
|
gr.Image(),
|
|
)
|
|
|
|
with gr.Blocks():
|
|
demo.render()
|
|
demo_2.render()
|
|
|
|
# Input/Output got saved to cache
|
|
assert len(list(gradio_temp_dir.glob("**/*.*"))) == 0
|
|
|
|
|
|
def test_time_to_live_and_delete_callback_for_state(capsys, monkeypatch):
|
|
monkeypatch.setenv("GRADIO_IS_E2E_TEST", "1")
|
|
|
|
def test_fn(x):
|
|
return x + 1, x + 1
|
|
|
|
def delete_fn(v):
|
|
print(f"deleted {v}")
|
|
|
|
with gr.Blocks() as demo:
|
|
n1 = gr.Number(value=0)
|
|
state = gr.State(
|
|
value=0, time_to_live=1, delete_callback=lambda v: delete_fn(v)
|
|
)
|
|
button = gr.Button("Increment")
|
|
button.click(test_fn, [state], [n1, state], api_name="increment")
|
|
|
|
app, url, _ = demo.launch(prevent_thread_lock=True)
|
|
|
|
try:
|
|
client_1 = grc.Client(url)
|
|
client_2 = grc.Client(url)
|
|
|
|
client_1.predict(api_name="/increment")
|
|
client_1.predict(api_name="/increment")
|
|
client_1.predict(api_name="/increment")
|
|
|
|
client_2.predict(api_name="/increment")
|
|
client_2.predict(api_name="/increment")
|
|
|
|
time.sleep(3)
|
|
|
|
captured = capsys.readouterr()
|
|
assert "deleted 2" in captured.out
|
|
assert "deleted 3" in captured.out
|
|
for client in [client_1, client_2]:
|
|
assert (
|
|
len(app.state_holder.session_data[client.session_hash].state_data) == 0 # type: ignore
|
|
)
|
|
finally:
|
|
demo.close()
|
|
|
|
|
|
def test_post_process_file_blocked(connect):
|
|
dotfile = pathlib.Path(".foo.txt")
|
|
file = pathlib.Path(os.getcwd()) / ".." / "file.txt"
|
|
|
|
try:
|
|
demo = gr.Interface(lambda s: s, "text", "file")
|
|
with connect(demo, show_error=True) as client:
|
|
_ = client.predict("test/test_files/bus.png")
|
|
with pytest.raises(
|
|
ValueError,
|
|
match="to the gradio cache dir because it was not created by",
|
|
):
|
|
file.write_text("Hi")
|
|
client.predict(str(file))
|
|
|
|
with connect(demo, allowed_paths=[str(file)]) as client:
|
|
_ = client.predict(str(file))
|
|
|
|
dotfile.write_text("foo")
|
|
with connect(demo, show_error=True) as client:
|
|
with pytest.raises(ValueError, match="Dotfiles located"):
|
|
_ = client.predict(str(dotfile))
|
|
|
|
with connect(demo, allowed_paths=[str(dotfile)]) as client:
|
|
_ = client.predict(str(dotfile))
|
|
|
|
finally:
|
|
try:
|
|
dotfile.unlink()
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
|
|
def test_render_when_mounted_sets_root_path_for_files():
|
|
app = FastAPI()
|
|
test_video_path = "test/test_files/video_sample.mp4"
|
|
|
|
with gr.Blocks() as demo:
|
|
text = gr.Text()
|
|
gr.Video(test_video_path)
|
|
|
|
@gr.render(inputs=text)
|
|
def show_video(data):
|
|
gr.Video(test_video_path)
|
|
|
|
app = gr.mount_gradio_app(app, demo, path="/test")
|
|
|
|
with TestClient(app) as client:
|
|
r = client.post(
|
|
f"/test{API_PREFIX}/queue/join",
|
|
json={
|
|
"data": [""],
|
|
"fn_index": 0,
|
|
"event_data": None,
|
|
"session_hash": "foo",
|
|
"trigger_id": None,
|
|
},
|
|
)
|
|
assert r.status_code == 200
|
|
r = client.get(f"/test{API_PREFIX}/queue/data?session_hash=foo")
|
|
checked_component = False
|
|
for msg in r.iter_lines():
|
|
if "data" in msg:
|
|
data = json.loads(msg[5:])
|
|
if data["msg"] == "process_completed":
|
|
render_config = data["output"]["render_config"]
|
|
for component in render_config["components"]:
|
|
if "value" in component.get("props", {}):
|
|
assert component["props"]["value"]["video"][
|
|
"url"
|
|
].startswith(f"http://testserver/test{API_PREFIX}/file=")
|
|
checked_component = True
|
|
assert checked_component
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_css_files():
|
|
css_contents = {
|
|
"file1.css": "h1 { font-size: 20px; }",
|
|
"file2.css": ".class { margin: 10px; }",
|
|
}
|
|
|
|
def mock_open_file(filename, encoding):
|
|
return mock_open(read_data=css_contents[filename])()
|
|
|
|
with patch("builtins.open", side_effect=mock_open_file):
|
|
yield
|
|
|
|
|
|
def test_css_and_css_paths_parameters(mock_css_files):
|
|
css_paths = ["file1.css", "file2.css"]
|
|
instance = gr.Blocks(css="body { color: red; }", css_paths=css_paths)
|
|
expected_css = """
|
|
body { color: red; }
|
|
h1 { font-size: 20px; }
|
|
.class { margin: 10px; }
|
|
"""
|
|
|
|
assert instance.css.strip() == expected_css.strip()
|