mirror of
https://github.com/gradio-app/gradio.git
synced 2025-01-30 11:00:11 +08:00
287fe67828
* 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 commit20dbf90811
. * 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 commita8ca614eaf
. * Delete bad * formatting * Revert "formatting" This reverts commit94f43859e7
. * 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 commit5916b3dc8a
. * 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>
1179 lines
45 KiB
Python
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,
|
|
)
|