gradio/test/test_blocks.py
Abubakar Abid 6f95286337
5.0 dev -> main (#8843)
* 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 commit e2a26e6d28.

* 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 commit 9e2ae43330.

* Revert "changes"

This reverts commit 9f4c3eec0f.

* 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 commit a89fcb1134.

* 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 commit 4605302df4.

* 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 commit 855b012a20.

* 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 commit 4605302df4.

* 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 commit 855b012a20.

* 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 commit 2e43584a87.

---------

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 commit 278645b649.

* 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 in 98cbcaef82/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 commit 40c9e396a1.

* Revert "test"

This reverts commit 660a6b06ea.

* 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>
2024-10-08 22:17:17 -07:00

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