gradio/client/python/test/test_client.py
pngwn 287fe67828
Version 4 development branch (#5498)
* squash commit

* BugFix: Make FileExplorer Component Templateable (#5933)

* Make FileExplorer templateable

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix notebooks (#5935)

* V4: Update Component pyi file (#5937)

* Add code

* add changeset

* delete

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Use beta release versions for '@gradio' packages (#5938)

* Fix versions

* add changeset

* fix

* add changeset

* fix

* add changeset

* Fix

* fix preview

* add changeset

* final fix

* add changeset

* fix

* add changeset

* fix

* add changeset

* revert change

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* maybe fix (#5946)

* Merge main again (#5948)

* maybe fix

* fix

* Merge main again (#5949)

* maybe fix

* fix

* weird weird weird

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Merge main again (#5950)

* maybe fix

* fix

* weird weird weird

* fix

* log

* log

* fix changesets

* rererefactor frontend files (#5960)

* do all the things

* add changeset

* remove codemod

* fix

* change casing

* condense upload button

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Strip vite import warning (#5962)

* Add code

* Remove comment

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5769)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* release wasm (#5963)

* release wasm

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Wasm release (#5964)

* release wasm

* release wasm

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5965)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Add json schema unit tests (#5970)

* Add tests

* add changeset

* Fix tests

* api-info

* Add test

* Add test

* Add email tests

* 3.8 fix 🙄

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Simple textbox (#5990)

* Simple textbox

* add changeset

* Trim down events

* Trim

* Clean up change event

* Add comment

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* File upload optimization (#5961)

* Use custom multipart parser

* add changeset

* remove print

* Add comment

* Lint

* fix code

* remove print

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Removes deprecated arguments and parameters from v4 (#5968)

* Removes deprecated arguments and methods for v4

* remove update

* style

* add changeset

* added params

* typign

* fixed all of the typing

* tests

* fix layouts

* layout

* fix config

* fix

* fix form

* fix

* fix blocks tests

* fix some more tests

* lint

* fix test routes

* doc

* notebooks

* remove doc

* format

* format

* remove group

* label docstring

* remov test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Simple dropdown (#5996)

* Add code

* lint

* comment

* add changeset

* revert

* Fix update + docstring cleanup

* Add code

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* pass props to example components and to example outputs (#6014)

* pass props to example components and to example outputs

* add changeset

* make util less egenric/ more useful

* fix demo

* fix demo

* fix

* fix test

* Fix test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>

* Format js in v4 branch (#6016)

* Format v4 branch js

* add changeset

* lint

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Fix component update bug  (#6027)

* Fix tests + bugs

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* lockfile update

* Fixing test

* fix test

* Add a cli command to list available templates (#6018)

* Add code

* dataset

* Add test

* add changeset

* add changeset

* add changeset

* add changeset

* Exclude FormComponent

* Paginate the output

* No colors but emojis:

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* fix tests (#6046)

* fix storybook (#6065)

* fix storybook

* add changeset

* fix

* add changeset

* fix

* fix

* fix components

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* remove dupe component (#6067)

* remove dupe component

* add changeset

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Simplify File Component (#6044)

* Add code

* Add code

* Add code

* Reuse code UploadButton

* Use two files for UploadButton

* Address feedback

* Lint

* add changeset

* Update js/uploadbutton/shared/UploadButton.svelte

Co-authored-by: pngwn <hello@pngwn.io>

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: pngwn <hello@pngwn.io>

* Clean up backend of `File` and `UploadButton` and change the return type of `preprocess()` from TemporaryFIle to string filepath (#6060)

* changes

* add changeset

* upload button

* file

* add changeset

* valid types

* fix tests

* address review

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix Dropdown Example component and example processing logic (#6075)

* fix examples

* helpers

* dropdown

* fix cc build (#6079)

* fix cc build

* add changeset

* throw error if build fails

* fix entry points

* add changeset

* fix lockfile

* Add test

* update workflow

* try resolve

* lint 🙄

* Use xfail

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>

* Fixes markdown rendering in examples (#6071)

* Fixes markdown rendering in examples

* add changeset

* update delimiters

* format

* format

* docstrings

* test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Proposal: sample demo for custom components should be a `gr.Interface` (#6077)

* update sample demo to interface

* add changeset

* modify

* Update gradio/cli/commands/components/_create_utils.py

Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com>

* added layout and static

* fix

* refine

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com>

* WIP: Fix docs (#6082)

* Website fix

* add changeset

* Fix code

* pin version

* Add code

* skip code

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Pending events behavior (#5826)

* enter changesets pre-release mode

* release first version (#5500)

* release packages

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* fix changeset (#5502)

* add changeset

* release first version

* Custom components (#5507)

* Add flag

* Copy front-end

* Add backend code

* Remove breakpoint

* Fix init

* Add code

* File reorg

* Fix types

* Upload files

* Fix code

* Custom components

* Add code

* Client changes

* More changes

* Add code

* Add code

* Fix reversion

* build hook integration

* Add code

* rm file

* Add code

* rename cli

* Add code

* Nicer cli

* Add display class

* Add backend devmide

* Add code?

* Add code

* Add paths and fix reload mdoe

* Fix .then

* changes

* fix

* fix

* changes

* changes

* changes

* Fix versions

* Fix wheel build from source

* Add code

* Get no template case working

* Cc fe (#5509)

* tweaks

* fix 18n

* fix 18n

* tweaks

* Change name

---------

Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>

* Do not use live display for dev mode

* Clean up front-end server print statements a little bit

* Fix success event

* Cc fe 2 (#5526)

* tweaks

* fix examples

* fix backend port

* fix things

* fix

* Fix json component flagging

* fix

* fuix

---------

Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>

* Fix template (#5533)

* Fix type hint (#5536)

* fix custom components when installed from wheel (#5552)

* Fix all demos custom components (#5555)

* Fix all_demos

* Fix issues

* trigger ci

* add changeset

* Fix merge

* lockfile

* Add code

* add code

* Fix command

* Add code

* Fix highlighted text

* fix interactive highlighted text

* tweak ci

* Disable example caching for load right now

---------

Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* image fixes (#5589)

* Add flag

* Copy front-end

* Add backend code

* Remove breakpoint

* Fix init

* Add code

* File reorg

* Fix types

* Upload files

* Fix code

* Custom components

* Add code

* Client changes

* More changes

* Add code

* Add code

* Fix reversion

* build hook integration

* Add code

* rm file

* Add code

* rename cli

* Add code

* Nicer cli

* Add display class

* Add backend devmide

* Add code?

* Add code

* Add paths and fix reload mdoe

* Fix .then

* changes

* fix

* fix

* changes

* changes

* changes

* Fix versions

* Fix wheel build from source

* Add code

* Get no template case working

* Cc fe (#5509)

* tweaks

* fix 18n

* fix 18n

* tweaks

* Change name

---------

Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>

* Do not use live display for dev mode

* Clean up front-end server print statements a little bit

* Fix success event

* Cc fe 2 (#5526)

* tweaks

* fix examples

* fix backend port

* fix things

* fix

* Fix json component flagging

* fix

* fuix

---------

Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>

* Fix template (#5533)

* Fix type hint (#5536)

* fix custom components when installed from wheel (#5552)

* Fix all demos custom components (#5555)

* Fix all_demos

* Fix issues

* trigger ci

* add changeset

* Fix merge

* lockfile

* Add code

* add code

* Fix command

* Add code

* Fix highlighted text

* fix interactive highlighted text

* tweak ci

* fix image uploads

* add changeset

* remove changeset

* add changeset

---------

Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Support Literal Typehints (#5591)

* Fix updateable

* Deploy for failing actions

* fix enum

* Add code

* remove gradio lite from publish ci

* fix

* fix

* chore: update versions (beta) (#5501)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Fix js deps in cli and add gradio-preview artifacts to build (#5610)

* Fix js dependencies in cli

* Add preview to build command

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5612)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* backend linting (#5613)

* backend linting

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Publish js theme (#5615)

* Publish js theme

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5614)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Add code (#5617)

* Add docstring to trigger release (#5618)

* Add docstring

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5619)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fix build and broken imports (#5620)

* fix broken import

* fix build scripts

* add changeset

* Update js/statustracker/static/index.svelte

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5621)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Fix esbuild (#5624)

* fix build

* fix build

* add changeset

* fix build

* fix

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5626)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Fix esbuild (#5629)

* fix build

* fix build

* add changeset

* fix build

* fix

* asd

* more fix

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* asd (#5630)

* chore: update versions (beta) (#5631)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Some minor v4 fixes (#5637)

* Add code

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Publish all components to npm (#5648)

* Publish image component

* publish components

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5638)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Fix front-end imports + other misc fixes (#5649)

* Fix console error

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Add overwrite flag to create command (#5651)

* Add overwrite flag to create command

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5650)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Make layout components templateable (#5665)

* Split out layouts

* Refactor cli

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Patch fixes (#5678)

* Handle lowercase template name frontend

* Lint

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix build and file route (#5680)

* Add code

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5662)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* V4 fix typing (#5686)

* Add examples for series and parallel

* v4 fix typing

* add changeset

* Fix

* Fix

* Fix 3.8

* Fix typing 3.8

* Lint

* Add code

* Add key

* Fix typing

* Add code

* Fix deps

* Fix fastapi

* Fix version
'
:

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Use overrides (#5695)

* Use overrides

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* ensure client is copied along with components (#5709)

* ensure client is copied along with components

* add changeset

* add changeset

* chore: update versions (beta) (#5688)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fix build config (#5710)

* Fix python unit tests for v4 (#5715)

* Add code

* Fix tests

* Add ci

* Add code

* fix test_blocks

* More fixes

* Last changes

* add changeset

* Add code

* Continue for the sake of some green ci

* Proper api info

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Better test dir check (#5719)

* FIx test-dir check

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Use path to npm executable in subprocess (#5736)

* Use path to npm in subprocess

* Fix dev mode too

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Add Error + test (#5738)

* Add Error + test

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix component regex (#5739)

* Add code

* Fix component regex

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix layout templates (#5740)

* Fix templates

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix template remaining components (#5743)

* add code

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* --overwrite deletes previous content (#5744)

* Add code

* Add code

* add changeset

* Add test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Support call method (#5751)

* Support call method

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix windows ci build (#5752)

* Try bash

* Use cross-env

* Trigger CI

* Fix comma

* add changeset

* Modify lock file

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix windows paths (#5745)

* Use posix path

* add changeset

* add changeset

* Try normalize

* to_posix v2

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* chore: update versions (beta) (#5717)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Simplify how files are handled in components in 4.0 (#5768)

* Client and upload route hash files

* Refactor logic

* add changeset

* Add code

* View API fix

* Fix client tests

* Dumb windows fix

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix deployed demos on v4 branch (#5770)

* Template fixes

* add changeset

* add changeset

* Fix streaming audio

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Name Endpoints if api_name is None (#5782)

* Implementation and test

* add changeset

* fix lint

* Fix nits

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* pending events

* add changeset

* Set api=False for cancel events (#5851)

* Set api=False for cancel events

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Set cache dir for some component tests (#5852)

* Add code

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Use async version of shutil in upload route (#5853)

* Use async shutil copy

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* trigger_mode

* changes

* undo

* undo

* add changeset

* undo

* add changeset

* image undo

* add changeset

* fix merge errors

* remove prints

* change

* fix

* fix error

* change

* quick fix

* trigger_mode param

* type

* value error

---------

Co-authored-by: pngwn <hello@pngwn.io>
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* Fixes: slider bar are too thin on FireFox (#5984)

* firefox slider fix

* add changeset

* fix

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* Fix remaining xfail tests in backend (#6073)

* Add code'

* Add code

* Add code

* Fix dataset

* add changeset

* Add some comments

* Add recover_kwargs

* Remove from docstring

* Audio-to-audio

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix dev mode model3D (#5955)

* Fix dev mode

* Lint

* add changeset

* Fix dev mode

* Lint

* remove console.log

* add changeset

* interactive fix

* Fix tests

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Dawood <dawoodkhan82@gmail.com>

* V4: Single-file implementation of form components (#6026)

* Checkbox and number

* Number, Checkboxgroup, Radio, and Slider

* Format

* remove range

* Refactor checkbox

* Forgot to add

* Refactor

* Lint

* add changeset

* use rich emoji markup

* Fix ts

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Update logos for v4 (#6089)

* update v4 logo

* add changeset

* size

* fix on website

* fix on demos

* add changeset

* favicon for demos

* margin on footer logo

* margin bottom to footer logo

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com>

* Add a stand-alone install command and tidy-up the fallback template (#6092)

* Add code

* add changeset

* Add test

* Make install default

* Better error message

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4: Fix constructor_args (#6093)

* Fix

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix: Move to cache in init postprocess + Fallback Fixes (#6107)

* Add code and test

* restore

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* fix build (#6112)

* fix build

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Update cold-lemons-roll.md

* Revert "Update cold-lemons-roll.md" (#6113)

This reverts commit 20dbf90811.

* Try to trigger a major beta release (#6114)

* pyproject fix

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Delete bad changelog (#6115)

* Delete bad changelog

* Revert "Delete bad changelog"

This reverts commit a8ca614eaf.

* Delete bad

* formatting

* Revert "formatting"

This reverts commit 94f43859e7.

* Improve Audio Component (#5966)

* replace <audio> with wavesurfer: add recording, playing and trimming, playback

* add changeset

* merge cleanup

* improving recording styling

* add recording timer

* add trim region duration

* allow trimming recordings

* clean up playing logic

* add pause_recording event

* remove crop min/max

* add waveform options param

* remove trimmingmode and use mode

* streaming + cleanup

* add changeset

* clean up types

* mobile adjustments

* add min/max length  + trim accessibility

* update pnpm lock

* amend source to a list and allow source switching

* fix no microphone found logic

* change undo logic to reset trims

* tweaks

* tweak reset logic

* ensure recording is sent to backend

* fix audio duration reactivity

* list tweak

* clean up

* change source -> sources + restore wasm changes

* formatting

* fix tests

* fix test

* add default sources value in fe + fix audio demos

* fix audio file name test

* add better sources typing

* ui test tweaks

* add default value in templates.py

* formatting

* remove unused prop

* add audio story

* add changeset

* revert sources changes

* remove story id

* fix be test

* fix be test

* fix notebooks

* formatting

* fix test

* fix test again

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
Co-authored-by: pngwn <hello@pngwn.io>

* Fix changesets 2 (#6116)

* fix changesets

* release major

* Fix changesets 2 (#6117)

* fix changesets

* release major

* asd

* fix version

* chore: update versions (beta) (#5973)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* v4

* Open source FRP server and allow `gradio` to connect to custom share servers (#6091)

* add param

* add support for custom address

* add changeset

* share guide

* guide

* add params

* add changeset

* fix launch

* add test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Gradio custom component publish (#6098)

* Add code

* add changeset

* F-string

* Add pwd

* Add source to space

* Add template

* Twine import

* add changeset

* ignore

* restore

* add changeset

* Address feedback

* Update gradio/cli/commands/components/publish.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>

* Fix static issues with Lite on v4 (#6124)

* fix missing props

* fix path to types

* add changeset

* fix path to i18n

* fix audio tests

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Ali Abid <aabid94@gmail.com>

* Refactor `Blocks.load()` so that it is in the same style as the other listeners (#6126)

* restore decorator

* remove

* refactor load

* remove restriction

* add changeset

* add pyi

* add test

* add test

* fix tests

* metaclass

* future

* reduce'

* docstring

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Small change to make `api_open=False` by default (#6138)

* set api_open to False by default

* add changeset

* tests

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Image v4 (#6094)

* simplify image interface

* changes

* asd

* asd

* more

* add code (#6095)

* more

* fix tests

* add changeset

* fix client build

* fix linting

* fix test

* lint

* Fix tests + lint

* asd

* finish

* webcam selection

* fix backend

* address comments

* fix static checks

* fix everything

* add changeset

* Apply suggestions from code review

Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* fix examples

* fix tests

* fix tests

---------

Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com>
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* Fix fallback demo app template code (#6129)

* Add test

* add changeset

* Add JSON note

* Fix test

* Update gradio/cli/commands/components/_create_utils.py

* Update test/test_gradio_component_cli.py

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* fix video path

* Revert "fix video path"

This reverts commit 5916b3dc8a.

* Fix selectable prop in the backend (#6135)

* Add to init

* Fix events

* add changeset

* Add code

* add changeset

* Fix typo

* Add code

* Fix highlighted text typo

* remove from docs

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix video (#6140)

* fix video

* add changeset

* fixes

* fixes

* lint

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* fix some tests on mac

* fix circular dependency with client + upload (#6143)

* fix circular dependency

* add changeset

* fix test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix image double change bug (#6146)

* fix test

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* make lite private (#6147)

* make lite private

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* fix dropdown arrow size (#6148)

* fix dropdown arrow size

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* swap `mode` on the frontned to `interactive` to match the backend (#6149)

* JS READMEs and Storybook on Docs (#6142)

* changes

* changes

* working

* remove storybook path

* add changeset

* pin code

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Don't serve files in working directory by default (#6128)

* don't serve files in working directory by default

* add changeset

* handle examples

* remove dotfiles

* guide

* guide

* fix tests

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Fix issues with website deploy (#6151)

* fixes

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Swap websockets for SSE (#6069)

* changes

* changes

* changes

* changes

* changes

* merge

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* add changeset

* changes

* changes

* changes

* add changeset

* changes

* changes

* changes

* add changeset

* changes

* changes

* changes

* add changeset

* changes

* changes

* changes

* changes

* changes

* add changeset

* Fix client tests sse branch (#6150)

* Switch spaces

* Fix tests

* Add code

* changes

* changes

---------

Co-authored-by: Ali Abid <aabid94@gmail.com>

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Freddy Boulton <alfonsoboulton@gmail.com>

* Remove duplicate `elem_ids` from components (#6152)

* remove elem_ids from components

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Moves `gradio_cached_folder` inside the gradio temp direcotry (#6155)

* cache -> temp

* restore

* add changeset

* add exception for cached examples

* security policy

* join

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Remove `show_edit_button` param in Audio (#6153)

* remove `show_edit_button` param

* add changeset

* hide overflow

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Remove interpretation for good (#6154)

* interpretation

* notebooks

* add changeset

* removed from readme

* lint

* fix demo

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Make output components not editable if they are being updated (#6157)

* make outputs not editable

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* JS Component Documentation (#6136)

* Simple template

* More changes

* Properly handle change event video

* add changeset

* Add code'

* Fix play/pause bugs

* add changeset

* atoms doc

* Chatbot

* add changeset

* Some more components

* Add code

* add changeset

* Lint

* add changeset

* Simple template

* More changes

* Properly handle change event video

* add changeset

* Add code'

* Fix play/pause bugs

* add changeset

* atoms doc

* Chatbot

* add changeset

* Some more components

* Add code

* add changeset

* Lint

* Merge in latest changes

* Fix typo

* Fix build

* Lockfile

* Fix

* Fix interactive

* correct the title

* add versions to readme

* only document public

* add changeset

* Remove simplevideo and audio

* add changeset

* changes to readmes

* add changeset

* remove tootils and theme

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com>

* Improve Video Component (#6118)

* change source to sources + add length logic

* add changeset

* add min/max logic

* tweak tests

* change sources

* formatting

* fix test_components.py test

* add trimming

* add changeset

* add keyboard events to trimming timeline

* UX improvements

* Add fix

* add loading status

* flip if webcam is only source

* generate notebooks

* remove scroll

* add file extension

* trim (#6156)

Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* add loading indicator to video

* ensure correct file ext is used

* tweak

* change where ffmpeg is loaded

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: freddyaboulton <alfonsoboulton@gmail.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>

* chore: update versions (beta) (#6122)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* V4 fixes (#6161)

* changes

* changes

* Pin 8.9 (#6162)

* Pending outputs fix (#6160)

* fix

* add changeset

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* Clean root url (#6159)

* clean

* cleanup

* formatting

* add changeset

* fe

* add changeset

* selectable

* block

* fix

* fixes

* fix update

* gradio/events

* configs

* remove

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

* V4 fixes (#6167)

* changes

* changes

* Fixes remaining backend tests (#6165)

* fix backend tests

* add changeset

* changes

* fix strings

* lint

* lint

* fixes

* delete test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>

---------

Co-authored-by: freddyaboulton <alfonsoboulton@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: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dawood Khan <dawoodkhan82@gmail.com>
Co-authored-by: Ali Abdalla <ali.si3luwa@gmail.com>
Co-authored-by: Hannah <hannahblair@users.noreply.github.com>
Co-authored-by: Ali Abid <aabid94@gmail.com>
2023-10-31 04:46:02 +00:00

1179 lines
45 KiB
Python

import json
import pathlib
import tempfile
import time
import uuid
from concurrent.futures import CancelledError, TimeoutError
from contextlib import contextmanager
from datetime import datetime, timedelta
from pathlib import Path
from unittest.mock import MagicMock, patch
import gradio as gr
import huggingface_hub
import pytest
import uvicorn
from fastapi import FastAPI
from gradio.networking import Server
from huggingface_hub.utils import RepositoryNotFoundError
from gradio_client import Client
from gradio_client.client import DEFAULT_TEMP_DIR
from gradio_client.utils import Communicator, ProgressUnit, Status, StatusUpdate
HF_TOKEN = "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" # Intentionally revealing this key for testing purposes
@contextmanager
def connect(
demo: gr.Blocks, serialize: bool = True, output_dir: str = DEFAULT_TEMP_DIR
):
_, local_url, _ = demo.launch(prevent_thread_lock=True)
try:
yield Client(local_url, serialize=serialize, output_dir=output_dir)
finally:
# A more verbose version of .close()
# because we should set a timeout
# the tests that call .cancel() can get stuck
# waiting for the thread to join
if demo.enable_queue:
demo._queue.close()
demo.is_running = False
demo.server.should_exit = True
demo.server.thread.join(timeout=1)
class TestClientPredictions:
@pytest.mark.flaky
def test_raise_error_invalid_state(self):
with pytest.raises(ValueError, match="invalid state"):
Client("gradio-tests/paused-space")
@pytest.mark.flaky
def test_numerical_to_label_space(self):
client = Client("gradio-tests/titanic-survival")
label = json.load(
open(client.predict("male", 77, 10, api_name="/predict")) # noqa: SIM115
)
assert label["label"] == "Perishes"
with pytest.raises(
ValueError,
match="This Gradio app might have multiple endpoints. Please specify an `api_name` or `fn_index`",
):
client.predict("male", 77, 10)
with pytest.raises(
ValueError,
match="Cannot find a function with `api_name`: predict. Did you mean to use a leading slash?",
):
client.predict("male", 77, 10, api_name="predict")
@pytest.mark.flaky
def test_numerical_to_label_space_v4(self):
client = Client("gradio-tests/titanic-survivalv4-sse")
label = client.predict("male", 77, 10, api_name="/predict")
assert label["label"] == "Perishes"
@pytest.mark.flaky
def test_private_space(self):
client = Client("gradio-tests/not-actually-private-space", hf_token=HF_TOKEN)
output = client.predict("abc", api_name="/predict")
assert output == "abc"
@pytest.mark.flaky
def test_private_space_v4(self):
client = Client(
"gradio-tests/not-actually-private-spacev4-sse", hf_token=HF_TOKEN
)
output = client.predict("abc", api_name="/predict")
assert output == "abc"
def test_state(self, increment_demo):
with connect(increment_demo) as client:
output = client.predict(api_name="/increment_without_queue")
assert output == 1
output = client.predict(api_name="/increment_without_queue")
assert output == 2
output = client.predict(api_name="/increment_without_queue")
assert output == 3
client.reset_session()
output = client.predict(api_name="/increment_without_queue")
assert output == 1
output = client.predict(api_name="/increment_with_queue")
assert output == 2
client.reset_session()
output = client.predict(api_name="/increment_with_queue")
assert output == 1
output = client.predict(api_name="/increment_with_queue")
assert output == 2
def test_job_status(self, calculator_demo):
with connect(calculator_demo) as client:
statuses = []
job = client.submit(5, "add", 4, api_name="/predict")
while not job.done():
time.sleep(0.1)
statuses.append(job.status())
assert statuses
# Messages are sorted by time
assert sorted([s.time for s in statuses if s]) == [
s.time for s in statuses if s
]
assert sorted([s.code for s in statuses if s]) == [
s.code for s in statuses if s
]
@pytest.mark.flaky
def test_intermediate_outputs(self, count_generator_demo):
with connect(count_generator_demo) as client:
job = client.submit(3, fn_index=0)
while not job.done():
time.sleep(0.1)
assert job.outputs() == [str(i) for i in range(3)]
outputs = []
for o in client.submit(3, fn_index=0):
outputs.append(o)
assert outputs == [str(i) for i in range(3)]
@pytest.mark.flaky
def test_intermediate_outputs_with_exception(self, count_generator_demo_exception):
with connect(count_generator_demo_exception) as client:
with pytest.raises(Exception):
client.predict(7, api_name="/count")
with pytest.raises(
ValueError, match="Cannot call predict on this function"
):
client.predict(5, api_name="/count_forever")
def test_break_in_loop_if_error(self, calculator_demo):
with connect(calculator_demo) as client:
job = client.submit("foo", "add", 4, fn_index=0)
output = list(job)
assert output == []
@pytest.mark.flaky
def test_timeout(self, sentiment_classification_demo):
with pytest.raises(TimeoutError):
with connect(sentiment_classification_demo.queue()) as client:
job = client.submit(api_name="/sleep")
job.result(timeout=0.05)
@pytest.mark.flaky
def test_timeout_no_queue(self, sentiment_classification_demo):
with pytest.raises(TimeoutError):
with connect(sentiment_classification_demo) as client:
job = client.submit(api_name="/sleep")
job.result(timeout=0.1)
def test_raises_exception(self, calculator_demo):
with pytest.raises(Exception):
with connect(calculator_demo) as client:
job = client.submit("foo", "add", 9, fn_index=0)
job.result()
def test_raises_exception_no_queue(self, sentiment_classification_demo):
with pytest.raises(Exception):
with connect(sentiment_classification_demo) as client:
job = client.submit([5], api_name="/sleep")
job.result()
def test_job_output_video(self, video_component):
with connect(video_component) as client:
job = client.submit(
{
"video": "https://huggingface.co/spaces/gradio/video_component/resolve/main/files/a.mp4"
},
fn_index=0,
)
assert Path(job.result()["video"]).exists()
assert (
Path(DEFAULT_TEMP_DIR).resolve()
in Path(job.result()["video"]).resolve().parents
)
temp_dir = tempfile.mkdtemp()
with connect(video_component, output_dir=temp_dir) as client:
job = client.submit(
{
"video": "https://huggingface.co/spaces/gradio/video_component/resolve/main/files/a.mp4"
},
fn_index=0,
)
assert Path(job.result()["video"]).exists()
assert (
Path(temp_dir).resolve()
in Path(job.result()["video"]).resolve().parents
)
def test_progress_updates(self, progress_demo):
with connect(progress_demo) as client:
job = client.submit("hello", api_name="/predict")
statuses = []
while not job.done():
statuses.append(job.status())
time.sleep(0.02)
assert any(s.code == Status.PROGRESS for s in statuses)
assert any(s.progress_data is not None for s in statuses)
all_progress_data = [
p for s in statuses if s.progress_data for p in s.progress_data
]
count = 0
for i in range(20):
unit = ProgressUnit(
index=i, length=20, unit="steps", progress=None, desc=None
)
count += unit in all_progress_data
assert count
def test_cancel_from_client_queued(self, cancel_from_client_demo):
with connect(cancel_from_client_demo) as client:
start = time.time()
job = client.submit(api_name="/long")
while not job.done():
if job.status().code == Status.STARTING:
job.cancel()
break
with pytest.raises(CancelledError):
job.result()
# The whole prediction takes 10 seconds to run
# and does not iterate. So this tests that we can cancel
# halfway through a prediction
assert time.time() - start < 10
assert job.status().code == Status.CANCELLED
job = client.submit(api_name="/iterate")
iteration_count = 0
while not job.done():
if job.status().code == Status.ITERATING:
iteration_count += 1
if iteration_count == 3:
job.cancel()
break
time.sleep(0.5)
# Result for iterative jobs will raise there is an exception
with pytest.raises(CancelledError):
job.result()
# The whole prediction takes 10 seconds to run
# and does not iterate. So this tests that we can cancel
# halfway through a prediction
assert time.time() - start < 10
# Test that we did not iterate all the way to the end
assert all(o in [0, 1, 2, 3, 4, 5] for o in job.outputs())
assert job.status().code == Status.CANCELLED
def test_cancel_subsequent_jobs_state_reset(self, yield_demo):
with connect(yield_demo) as client:
job1 = client.submit("abcdefefadsadfs", api_name="/predict")
time.sleep(3)
job1.cancel()
assert len(job1.outputs()) > 0
assert len(job1.outputs()) < len("abcdefefadsadfs")
assert job1.status().code == Status.CANCELLED
job2 = client.submit("abcd", api_name="/predict")
assert len(job2.outputs()) == 0
while not job2.done():
time.sleep(0.1)
# Ran all iterations from scratch
assert job2.status().code == Status.FINISHED
assert len(job2.outputs()) == 4
@pytest.mark.xfail
def test_stream_audio(self, stream_audio):
with connect(stream_audio) as client:
job1 = client.submit(
"https://gradio-builds.s3.amazonaws.com/demo-files/bark_demo.mp4",
api_name="/predict",
)
assert Path(job1.result()).exists()
job2 = client.submit(
"https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav",
api_name="/predict",
)
assert Path(job2.result()).exists()
assert all(Path(p).exists() for p in job2.outputs())
@pytest.mark.xfail
def test_upload_file_private_space_v4(self):
client = Client(
src="gradio-tests/not-actually-private-file-uploadv4-sse", hf_token=HF_TOKEN
)
with patch.object(
client.endpoints[0], "_upload", wraps=client.endpoints[0]._upload
) as upload:
with patch.object(
client.endpoints[0], "serialize", wraps=client.endpoints[0].serialize
) as serialize:
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
f.write("Hello from private space!")
output = client.submit(
1, "foo", f.name, api_name="/file_upload"
).result()
with open(output) as f:
assert f.read() == "Hello from private space!"
upload.assert_called_once()
assert all(f["is_file"] for f in serialize.return_value())
with patch.object(
client.endpoints[1], "_upload", wraps=client.endpoints[0]._upload
) as upload:
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
f.write("Hello from private space!")
with open(client.submit(f.name, api_name="/upload_btn").result()) as f:
assert f.read() == "Hello from private space!"
upload.assert_called_once()
with patch.object(
client.endpoints[2], "_upload", wraps=client.endpoints[0]._upload
) as upload:
# `delete=False` is required for Windows compat
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f1:
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f2:
f1.write("File1")
f2.write("File2")
r1, r2 = client.submit(
3,
[f1.name, f2.name],
"hello",
api_name="/upload_multiple",
).result()
with open(r1) as f:
assert f.read() == "File1"
with open(r2) as f:
assert f.read() == "File2"
upload.assert_called_once()
@pytest.mark.flaky
def test_upload_file_private_space(self):
client = Client(
src="gradio-tests/not-actually-private-file-upload", hf_token=HF_TOKEN
)
with patch.object(
client.endpoints[0], "serialize", wraps=client.endpoints[0].serialize
) as serialize:
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
f.write("Hello from private space!")
output = client.submit(1, "foo", f.name, api_name="/file_upload").result()
with open(output) as f:
assert f.read() == "Hello from private space!"
assert all(f["is_file"] for f in serialize.return_value())
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
f.write("Hello from private space!")
with open(client.submit(f.name, api_name="/upload_btn").result()) as f:
assert f.read() == "Hello from private space!"
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f1:
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f2:
f1.write("File1")
f2.write("File2")
r1, r2 = client.submit(
3,
[f1.name, f2.name],
"hello",
api_name="/upload_multiple",
).result()
with open(r1) as f:
assert f.read() == "File1"
with open(r2) as f:
assert f.read() == "File2"
@pytest.mark.flaky
def test_upload_file_upload_route_does_not_exist(self):
client = Client(
src="gradio-tests/not-actually-private-file-upload-old-version",
hf_token=HF_TOKEN,
)
with patch.object(
client.endpoints[0], "serialize", wraps=client.endpoints[0].serialize
) as serialize:
with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
f.write("Hello from private space!")
client.submit(1, "foo", f.name, fn_index=0).result()
serialize.assert_called_once_with(1, "foo", f.name)
def test_state_without_serialize(self, stateful_chatbot):
with connect(stateful_chatbot, serialize=False) as client:
initial_history = [["", None]]
message = "Hello"
ret = client.predict(message, initial_history, api_name="/submit")
assert ret == ("", [["", None], ["Hello", "I love you"]])
def test_can_call_mounted_app_via_api(self):
def greet(name):
return "Hello " + name + "!"
gradio_app = gr.Interface(
fn=greet,
inputs=gr.Textbox(lines=2, placeholder="Name Here..."),
outputs="text",
)
app = FastAPI()
app = gr.mount_gradio_app(app, gradio_app, path="/test/gradio")
config = uvicorn.Config(
app=app,
port=8000,
log_level="info",
)
server = Server(config=config)
# Using the gradio Server class to not have
# to implement code again to run uvicorn in a separate thread
# However, that means we need to set this flag to prevent
# run_in_thread_from_blocking
server.started = True
try:
server.run_in_thread()
time.sleep(1)
client = Client("http://127.0.0.1:8000/test/gradio/")
assert client.predict("freddy") == "Hello freddy!"
finally:
server.thread.join(timeout=1)
def test_predict_with_space_with_api_name_false(self):
client = Client("gradio-tests/client-bool-api-name-error")
assert client.predict("Hello!", api_name="/run") == "Hello!"
assert client.predict("Freddy", api_name="/say_hello") == "hello"
def test_return_layout_component(self, hello_world_with_group):
with connect(hello_world_with_group) as demo:
assert demo.predict("Freddy", api_name="/greeting") == "Hello Freddy"
assert demo.predict(api_name="/show_group") == ()
def test_return_layout_and_state_components(
self, hello_world_with_state_and_accordion
):
with connect(hello_world_with_state_and_accordion) as demo:
assert demo.predict("Freddy", api_name="/greeting") == ("Hello Freddy", 1)
assert demo.predict("Abubakar", api_name="/greeting") == (
"Hello Abubakar",
2,
)
assert demo.predict(api_name="/open") == 3
assert demo.predict(api_name="/close") == 4
assert demo.predict("Ali", api_name="/greeting") == ("Hello Ali", 5)
class TestStatusUpdates:
@patch("gradio_client.client.Endpoint.make_end_to_end_fn")
def test_messages_passed_correctly(self, mock_make_end_to_end_fn, calculator_demo):
now = datetime.now()
messages = [
StatusUpdate(
code=Status.STARTING,
eta=None,
rank=None,
success=None,
queue_size=None,
time=now,
progress_data=None,
),
StatusUpdate(
code=Status.SENDING_DATA,
eta=None,
rank=None,
success=None,
queue_size=None,
time=now + timedelta(seconds=1),
progress_data=None,
),
StatusUpdate(
code=Status.IN_QUEUE,
eta=3,
rank=2,
queue_size=2,
success=None,
time=now + timedelta(seconds=2),
progress_data=None,
),
StatusUpdate(
code=Status.IN_QUEUE,
eta=2,
rank=1,
queue_size=1,
success=None,
time=now + timedelta(seconds=3),
progress_data=None,
),
StatusUpdate(
code=Status.ITERATING,
eta=None,
rank=None,
queue_size=None,
success=None,
time=now + timedelta(seconds=3),
progress_data=None,
),
StatusUpdate(
code=Status.FINISHED,
eta=None,
rank=None,
queue_size=None,
success=True,
time=now + timedelta(seconds=4),
progress_data=None,
),
]
class MockEndToEndFunction:
def __init__(self, communicator: Communicator):
self.communicator = communicator
def __call__(self, *args, **kwargs):
for m in messages:
with self.communicator.lock:
self.communicator.job.latest_status = m
time.sleep(0.1)
mock_make_end_to_end_fn.side_effect = MockEndToEndFunction
with connect(calculator_demo) as client:
job = client.submit(5, "add", 6, api_name="/predict")
statuses = []
while not job.done():
statuses.append(job.status())
time.sleep(0.09)
assert all(s in messages for s in statuses)
@patch("gradio_client.client.Endpoint.make_end_to_end_fn")
def test_messages_correct_two_concurrent(
self, mock_make_end_to_end_fn, calculator_demo
):
now = datetime.now()
messages_1 = [
StatusUpdate(
code=Status.STARTING,
eta=None,
rank=None,
success=None,
queue_size=None,
time=now,
progress_data=None,
),
StatusUpdate(
code=Status.FINISHED,
eta=None,
rank=None,
queue_size=None,
success=True,
time=now + timedelta(seconds=4),
progress_data=None,
),
]
messages_2 = [
StatusUpdate(
code=Status.IN_QUEUE,
eta=3,
rank=2,
queue_size=2,
success=None,
time=now + timedelta(seconds=2),
progress_data=None,
),
StatusUpdate(
code=Status.IN_QUEUE,
eta=2,
rank=1,
queue_size=1,
success=None,
time=now + timedelta(seconds=3),
progress_data=None,
),
]
class MockEndToEndFunction:
n_counts = 0
def __init__(self, communicator: Communicator):
self.communicator = communicator
self.messages = (
messages_1 if MockEndToEndFunction.n_counts == 0 else messages_2
)
MockEndToEndFunction.n_counts += 1
def __call__(self, *args, **kwargs):
for m in self.messages:
with self.communicator.lock:
print(f"here: {m}")
self.communicator.job.latest_status = m
time.sleep(0.1)
mock_make_end_to_end_fn.side_effect = MockEndToEndFunction
with connect(calculator_demo) as client:
job_1 = client.submit(5, "add", 6, api_name="/predict")
job_2 = client.submit(11, "subtract", 1, api_name="/predict")
statuses_1 = []
statuses_2 = []
while not (job_1.done() and job_2.done()):
statuses_1.append(job_1.status())
statuses_2.append(job_2.status())
time.sleep(0.05)
assert all(s in messages_1 for s in statuses_1)
class TestAPIInfo:
@pytest.mark.parametrize("trailing_char", ["/", ""])
def test_test_endpoint_src(self, trailing_char):
src = "https://gradio-calculator.hf.space" + trailing_char
client = Client(src=src)
assert client.endpoints[0].root_url == "https://gradio-calculator.hf.space/"
@pytest.mark.flaky
def test_numerical_to_label_space(self):
client = Client("gradio-tests/titanic-survival")
assert client.view_api(return_format="dict") == {
"named_endpoints": {
"/predict": {
"parameters": [
{
"label": "Sex",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Radio",
"example_input": "Howdy!",
"serializer": "StringSerializable",
},
{
"label": "Age",
"type": {"type": "number"},
"python_type": {"type": "int | float", "description": ""},
"component": "Slider",
"example_input": 5,
"serializer": "NumberSerializable",
},
{
"label": "Fare (british pounds)",
"type": {"type": "number"},
"python_type": {"type": "int | float", "description": ""},
"component": "Slider",
"example_input": 5,
"serializer": "NumberSerializable",
},
],
"returns": [
{
"label": "output",
"type": {"type": {}, "description": "any valid json"},
"python_type": {
"type": "str",
"description": "filepath to JSON file",
},
"component": "Label",
"serializer": "JSONSerializable",
}
],
},
"/predict_1": {
"parameters": [
{
"label": "Sex",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Radio",
"example_input": "Howdy!",
"serializer": "StringSerializable",
},
{
"label": "Age",
"type": {"type": "number"},
"python_type": {"type": "int | float", "description": ""},
"component": "Slider",
"example_input": 5,
"serializer": "NumberSerializable",
},
{
"label": "Fare (british pounds)",
"type": {"type": "number"},
"python_type": {"type": "int | float", "description": ""},
"component": "Slider",
"example_input": 5,
"serializer": "NumberSerializable",
},
],
"returns": [
{
"label": "output",
"type": {"type": {}, "description": "any valid json"},
"python_type": {
"type": "str",
"description": "filepath to JSON file",
},
"component": "Label",
"serializer": "JSONSerializable",
}
],
},
"/predict_2": {
"parameters": [
{
"label": "Sex",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Radio",
"example_input": "Howdy!",
"serializer": "StringSerializable",
},
{
"label": "Age",
"type": {"type": "number"},
"python_type": {"type": "int | float", "description": ""},
"component": "Slider",
"example_input": 5,
"serializer": "NumberSerializable",
},
{
"label": "Fare (british pounds)",
"type": {"type": "number"},
"python_type": {"type": "int | float", "description": ""},
"component": "Slider",
"example_input": 5,
"serializer": "NumberSerializable",
},
],
"returns": [
{
"label": "output",
"type": {"type": {}, "description": "any valid json"},
"python_type": {
"type": "str",
"description": "filepath to JSON file",
},
"component": "Label",
"serializer": "JSONSerializable",
}
],
},
},
"unnamed_endpoints": {},
}
def test_state_does_not_appear(self, state_demo):
with connect(state_demo) as client:
api_info = client.view_api(return_format="dict")
assert isinstance(api_info, dict)
for parameter in api_info["named_endpoints"]["/predict"]["parameters"]:
assert parameter["component"] != "State"
@pytest.mark.flaky
def test_private_space(self):
client = Client("gradio-tests/not-actually-private-space", hf_token=HF_TOKEN)
assert len(client.endpoints) == 3
assert len([e for e in client.endpoints if e.is_valid]) == 2
assert len([e for e in client.endpoints if e.is_valid and e.api_name]) == 1
assert client.view_api(return_format="dict") == {
"named_endpoints": {
"/predict": {
"parameters": [
{
"label": "x",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Textbox",
"example_input": "Howdy!",
"serializer": "StringSerializable",
}
],
"returns": [
{
"label": "output",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Textbox",
"serializer": "StringSerializable",
}
],
}
},
"unnamed_endpoints": {},
}
@pytest.mark.flaky
def test_fetch_fixed_version_space(self, calculator_demo):
with connect(calculator_demo) as client:
assert client.view_api(return_format="dict") == {
"named_endpoints": {
"/predict": {
"parameters": [
{
"label": "num1",
"type": {"type": "number"},
"python_type": {
"type": "float",
"description": "",
},
"component": "Number",
"example_input": 3,
},
{
"label": "operation",
"type": {
"enum": ["add", "subtract", "multiply", "divide"],
"title": "Radio",
"type": "string",
},
"python_type": {
"type": "Literal[add, subtract, multiply, divide]",
"description": "",
},
"component": "Radio",
"example_input": "add",
},
{
"label": "num2",
"type": {"type": "number"},
"python_type": {
"type": "float",
"description": "",
},
"component": "Number",
"example_input": 3,
},
],
"returns": [
{
"label": "output",
"type": {"type": "number"},
"python_type": {
"type": "float",
"description": "",
},
"component": "Number",
}
],
}
},
"unnamed_endpoints": {},
}
def test_unnamed_endpoints_use_fn_index(self, count_generator_demo):
with connect(count_generator_demo) as client:
info = client.view_api(return_format="str")
assert "fn_index" not in info
assert "api_name" in info
def test_api_false_endpoints_do_not_appear(self, count_generator_no_api):
with connect(count_generator_no_api) as client:
info = client.view_api(return_format="dict")
assert len(info["named_endpoints"]) == 0
def test_api_false_endpoints_cannot_be_accessed_with_fn_index(self, increment_demo):
with connect(increment_demo) as client:
with pytest.raises(ValueError):
client.submit(1, fn_index=2)
def test_file_io(self, file_io_demo):
with connect(file_io_demo) as client:
info = client.view_api(return_format="dict")
inputs = info["named_endpoints"]["/predict"]["parameters"]
outputs = info["named_endpoints"]["/predict"]["returns"]
assert inputs[0]["type"]["type"] == "array"
assert inputs[0]["python_type"] == {
"type": "List[filepath]",
"description": "",
}
assert isinstance(inputs[0]["example_input"], list)
assert isinstance(inputs[0]["example_input"][0], str)
assert inputs[1]["python_type"] == {
"type": "filepath",
"description": "",
}
assert isinstance(inputs[1]["example_input"], str)
assert outputs[0]["python_type"] == {
"type": "List[filepath]",
"description": "",
}
assert outputs[0]["type"]["type"] == "array"
assert outputs[1]["python_type"] == {
"type": "filepath",
"description": "",
}
def test_layout_components_in_output(self, hello_world_with_group):
with connect(hello_world_with_group) as client:
info = client.view_api(return_format="dict")
assert info == {
"named_endpoints": {
"/greeting": {
"parameters": [
{
"label": "name",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Textbox",
"example_input": "Hello!!",
}
],
"returns": [
{
"label": "greeting",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Textbox",
}
],
},
"/show_group": {"parameters": [], "returns": []},
},
"unnamed_endpoints": {},
}
def test_layout_and_state_components_in_output(
self, hello_world_with_state_and_accordion
):
with connect(hello_world_with_state_and_accordion) as client:
info = client.view_api(return_format="dict")
assert info == {
"named_endpoints": {
"/greeting": {
"parameters": [
{
"label": "name",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Textbox",
"example_input": "Hello!!",
}
],
"returns": [
{
"label": "greeting",
"type": {"type": "string"},
"python_type": {"type": "str", "description": ""},
"component": "Textbox",
},
{
"label": "count",
"type": {"type": "number"},
"python_type": {
"type": "float",
"description": "",
},
"component": "Number",
},
],
},
"/open": {
"parameters": [],
"returns": [
{
"label": "count",
"type": {"type": "number"},
"python_type": {
"type": "float",
"description": "",
},
"component": "Number",
}
],
},
"/close": {
"parameters": [],
"returns": [
{
"label": "count",
"type": {"type": "number"},
"python_type": {
"type": "float",
"description": "",
},
"component": "Number",
}
],
},
},
"unnamed_endpoints": {},
}
class TestEndpoints:
def test_upload(self):
client = Client(
src="gradio-tests/not-actually-private-file-upload", hf_token=HF_TOKEN
)
response = MagicMock(status_code=200)
response.json.return_value = [
"file1",
"file2",
"file3",
"file4",
"file5",
"file6",
"file7",
]
with patch("requests.post", MagicMock(return_value=response)):
with patch("builtins.open", MagicMock()):
with patch.object(pathlib.Path, "name") as mock_name:
mock_name.side_effect = lambda x: x
results = client.endpoints[0]._upload(
["pre1", ["pre2", "pre3", "pre4"], ["pre5", "pre6"], "pre7"]
)
res = []
for re in results:
if isinstance(re, list):
res.append([r["name"] for r in re])
else:
res.append(re["name"])
assert res == [
"file1",
["file2", "file3", "file4"],
["file5", "file6"],
"file7",
]
def test_upload_v4(self):
client = Client(
src="gradio-tests/not-actually-private-file-uploadv4-sse", hf_token=HF_TOKEN
)
response = MagicMock(status_code=200)
response.json.return_value = [
"file1",
"file2",
"file3",
"file4",
"file5",
"file6",
"file7",
]
with patch("requests.post", MagicMock(return_value=response)):
with patch("builtins.open", MagicMock()):
with patch.object(pathlib.Path, "name") as mock_name:
mock_name.side_effect = lambda x: x
results = client.endpoints[0]._upload(
["pre1", ["pre2", "pre3", "pre4"], ["pre5", "pre6"], "pre7"]
)
res = []
for re in results:
if isinstance(re, list):
res.append([r["path"] for r in re])
else:
res.append(re["path"])
assert res == [
"file1",
["file2", "file3", "file4"],
["file5", "file6"],
"file7",
]
cpu = huggingface_hub.SpaceHardware.CPU_BASIC
class TestDuplication:
@pytest.mark.flaky
@patch("huggingface_hub.get_space_runtime", return_value=MagicMock(hardware=cpu))
@patch("gradio_client.client.Client.__init__", return_value=None)
def test_new_space_id(self, mock_init, mock_runtime):
Client.duplicate("gradio/calculator", "test", hf_token=HF_TOKEN)
mock_runtime.assert_any_call("gradio/calculator", token=HF_TOKEN)
mock_runtime.assert_any_call("gradio-tests/test", token=HF_TOKEN)
mock_init.assert_called_with(
"gradio-tests/test", hf_token=HF_TOKEN, max_workers=40, verbose=True
)
Client.duplicate("gradio/calculator", "gradio-tests/test", hf_token=HF_TOKEN)
mock_runtime.assert_any_call("gradio/calculator", token=HF_TOKEN)
mock_runtime.assert_any_call("gradio-tests/test", token=HF_TOKEN)
mock_init.assert_called_with(
"gradio-tests/test", hf_token=HF_TOKEN, max_workers=40, verbose=True
)
@pytest.mark.flaky
@patch("gradio_client.utils.set_space_timeout")
@patch("huggingface_hub.get_space_runtime", return_value=MagicMock(hardware=cpu))
@patch("gradio_client.client.Client.__init__", return_value=None)
def test_dont_set_timeout_if_default_hardware(
self, mock_init, mock_runtime, mock_set_timeout
):
Client.duplicate("gradio/calculator", "test", hf_token=HF_TOKEN)
mock_set_timeout.assert_not_called()
@pytest.mark.flaky
@patch("huggingface_hub.request_space_hardware")
@patch("gradio_client.utils.set_space_timeout")
@patch(
"huggingface_hub.get_space_runtime",
return_value=MagicMock(hardware=huggingface_hub.SpaceHardware.CPU_UPGRADE),
)
@patch("gradio_client.client.Client.__init__", return_value=None)
def test_set_timeout_if_not_default_hardware(
self, mock_init, mock_runtime, mock_set_timeout, mock_request_hardware
):
Client.duplicate(
"gradio/calculator",
"test",
hf_token=HF_TOKEN,
hardware="cpu-upgrade",
sleep_timeout=15,
)
mock_set_timeout.assert_called_once_with(
"gradio-tests/test", hf_token=HF_TOKEN, timeout_in_seconds=15 * 60
)
@pytest.mark.flaky
@patch("huggingface_hub.get_space_runtime", return_value=MagicMock(hardware=cpu))
@patch("gradio_client.client.Client.__init__", return_value=None)
def test_default_space_id(self, mock_init, mock_runtime):
Client.duplicate("gradio/calculator", hf_token=HF_TOKEN)
mock_runtime.assert_any_call("gradio/calculator", token=HF_TOKEN)
mock_runtime.assert_any_call("gradio-tests/calculator", token=HF_TOKEN)
mock_init.assert_called_with(
"gradio-tests/calculator", hf_token=HF_TOKEN, max_workers=40, verbose=True
)
@pytest.mark.flaky
@patch("huggingface_hub.add_space_secret")
@patch("huggingface_hub.duplicate_space")
@patch("gradio_client.client.Client.__init__", return_value=None)
@patch("gradio_client.utils.set_space_timeout")
def test_add_secrets(self, mock_time, mock_init, mock_duplicate, mock_add_secret):
with pytest.raises(RepositoryNotFoundError):
name = str(uuid.uuid4())
Client.duplicate(
"gradio/calculator",
name,
hf_token=HF_TOKEN,
secrets={"test_key": "test_value", "test_key2": "test_value2"},
)
mock_add_secret.assert_called_with(
f"gradio-tests/{name}",
"test_key",
"test_value",
token=HF_TOKEN,
)
mock_add_secret.assert_any_call(
f"gradio-tests/{name}",
"test_key2",
"test_value2",
token=HF_TOKEN,
)