mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-17 11:29:58 +08:00
Check for file_types
parameter in the backend (#9431)
* file check fix * format * add changeset * tests * add changeset * Update gradio/components/file.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * Update client/python/gradio_client/utils.py Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * fixes * fixes * test fix * test fix * test --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
parent
c307a0c9b8
commit
7065e11e46
6
.changeset/thirty-cloths-taste.md
Normal file
6
.changeset/thirty-cloths-taste.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"gradio": patch
|
||||
"gradio_client": patch
|
||||
---
|
||||
|
||||
fix:Check for `file_types` parameter in the backend
|
@ -687,6 +687,23 @@ def get_extension(encoding: str) -> str | None:
|
||||
return extension
|
||||
|
||||
|
||||
def is_valid_file(file_path: str, file_types: list[str]) -> bool:
|
||||
mime_type = get_mimetype(file_path)
|
||||
if mime_type is None:
|
||||
return False
|
||||
for file_type in file_types:
|
||||
if file_type == "file":
|
||||
return True
|
||||
if file_type.startswith("."):
|
||||
file_type = file_type.lstrip(".").lower()
|
||||
mime_type_split = mime_type.lower().split("/")
|
||||
if file_type == mime_type_split[1]:
|
||||
return True
|
||||
elif mime_type.startswith(f"{file_type}/"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def encode_file_to_base64(f: str | Path):
|
||||
with open(f, "rb") as file:
|
||||
encoded_string = base64.b64encode(file.read())
|
||||
|
@ -71,6 +71,21 @@ def test_decode_base64_to_file():
|
||||
assert isinstance(temp_file, tempfile._TemporaryFileWrapper)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path_or_url, file_types, expected_result",
|
||||
[
|
||||
("/home/user/documents/example.pdf", [".json", "text", ".mp3", ".pdf"], True),
|
||||
("C:\\Users\\user\\documents\\example.png", [".png"], True),
|
||||
("C:\\Users\\user\\documents\\example.png", ["image"], True),
|
||||
("C:\\Users\\user\\documents\\example.png", ["file"], True),
|
||||
("/home/user/documents/example.pdf", [".json", "text", ".mp3"], False),
|
||||
("https://example.com/avatar/xxxx.mp4", ["audio", ".png", ".jpg"], False),
|
||||
],
|
||||
)
|
||||
def test_is_valid_file_type(path_or_url, file_types, expected_result):
|
||||
assert utils.is_valid_file(path_or_url, file_types) is expected_result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"orig_filename, new_filename",
|
||||
[
|
||||
|
@ -1 +1 @@
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: file_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def delete_file(n: int, file: gr.DeletedFileData):\n", " return [file.file.path, n + 1]\n", "\n", "with gr.Blocks() as demo:\n", "\n", " with gr.Row():\n", " with gr.Column():\n", " file_component = gr.File(label=\"Upload Single File\", file_count=\"single\")\n", " with gr.Column():\n", " output_file_1 = gr.File(\n", " label=\"Upload Single File Output\", file_count=\"single\"\n", " )\n", " num_load_btn_1 = gr.Number(label=\"# Load Upload Single File\", value=0)\n", " file_component.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component, num_load_btn_1],\n", " [output_file_1, num_load_btn_1],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_multiple = gr.File(\n", " label=\"Upload Multiple Files\", file_count=\"multiple\"\n", " )\n", " with gr.Column():\n", " output_file_2 = gr.File(\n", " label=\"Upload Multiple Files Output\", file_count=\"multiple\"\n", " )\n", " num_load_btn_2 = gr.Number(label=\"# Load Upload Multiple Files\", value=0)\n", " file_component_multiple.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_multiple, num_load_btn_2],\n", " [output_file_2, num_load_btn_2],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_specific = gr.File(\n", " label=\"Upload Multiple Files Image/Video\",\n", " file_count=\"multiple\",\n", " file_types=[\"image\", \"video\"],\n", " )\n", " with gr.Column():\n", " output_file_3 = gr.File(\n", " label=\"Upload Multiple Files Output Image/Video\", file_count=\"multiple\"\n", " )\n", " num_load_btn_3 = gr.Number(\n", " label=\"# Load Upload Multiple Files Image/Video\", value=0\n", " )\n", " file_component_specific.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_specific, num_load_btn_3],\n", " [output_file_3, num_load_btn_3],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_pdf = gr.File(label=\"Upload PDF File\", file_types=[\"pdf\"])\n", " with gr.Column():\n", " output_file_4 = gr.File(label=\"Upload PDF File Output\")\n", " num_load_btn_4 = gr.Number(label=\"# Load Upload PDF File\", value=0)\n", " file_component_pdf.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_pdf, num_load_btn_4],\n", " [output_file_4, num_load_btn_4],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_invalid = gr.File(\n", " label=\"Upload File with Invalid file_types\",\n", " file_types=[\"invalid file_type\"],\n", " )\n", " with gr.Column():\n", " output_file_5 = gr.File(label=\"Upload File with Invalid file_types Output\")\n", " num_load_btn_5 = gr.Number(\n", " label=\"# Load Upload File with Invalid file_types\", value=0\n", " )\n", " file_component_invalid.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_invalid, num_load_btn_5],\n", " [output_file_5, num_load_btn_5],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " del_file_input = gr.File(label=\"Delete File\", file_count=\"multiple\")\n", " with gr.Column():\n", " del_file_data = gr.Textbox(label=\"Delete file data\")\n", " num_load_btn_6 = gr.Number(label=\"# Deleted File\", value=0)\n", " del_file_input.delete(\n", " delete_file,\n", " [num_load_btn_6],\n", " [del_file_data, num_load_btn_6],\n", " )\n", " # f = gr.File(label=\"Upload many File\", file_count=\"multiple\")\n", " # # f.delete(delete_file)\n", " # f.delete(delete_file, inputs=None, outputs=None)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: file_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def delete_file(n: int, file: gr.DeletedFileData):\n", " return [file.file.path, n + 1]\n", "\n", "with gr.Blocks() as demo:\n", "\n", " with gr.Row():\n", " with gr.Column():\n", " file_component = gr.File(label=\"Upload Single File\", file_count=\"single\")\n", " with gr.Column():\n", " output_file_1 = gr.File(\n", " label=\"Upload Single File Output\", file_count=\"single\"\n", " )\n", " num_load_btn_1 = gr.Number(label=\"# Load Upload Single File\", value=0)\n", " file_component.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component, num_load_btn_1],\n", " [output_file_1, num_load_btn_1],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_multiple = gr.File(\n", " label=\"Upload Multiple Files\", file_count=\"multiple\"\n", " )\n", " with gr.Column():\n", " output_file_2 = gr.File(\n", " label=\"Upload Multiple Files Output\", file_count=\"multiple\"\n", " )\n", " num_load_btn_2 = gr.Number(label=\"# Load Upload Multiple Files\", value=0)\n", " file_component_multiple.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_multiple, num_load_btn_2],\n", " [output_file_2, num_load_btn_2],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_specific = gr.File(\n", " label=\"Upload Multiple Files Image/Video\",\n", " file_count=\"multiple\",\n", " file_types=[\"image\", \"video\"],\n", " )\n", " with gr.Column():\n", " output_file_3 = gr.File(\n", " label=\"Upload Multiple Files Output Image/Video\", file_count=\"multiple\"\n", " )\n", " num_load_btn_3 = gr.Number(\n", " label=\"# Load Upload Multiple Files Image/Video\", value=0\n", " )\n", " file_component_specific.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_specific, num_load_btn_3],\n", " [output_file_3, num_load_btn_3],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_pdf = gr.File(label=\"Upload PDF File\", file_types=[\".pdf\"])\n", " with gr.Column():\n", " output_file_4 = gr.File(label=\"Upload PDF File Output\")\n", " num_load_btn_4 = gr.Number(label=\"# Load Upload PDF File\", value=0)\n", " file_component_pdf.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_pdf, num_load_btn_4],\n", " [output_file_4, num_load_btn_4],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " file_component_invalid = gr.File(\n", " label=\"Upload File with Invalid file_types\",\n", " file_types=[\"invalid file_type\"],\n", " )\n", " with gr.Column():\n", " output_file_5 = gr.File(label=\"Upload File with Invalid file_types Output\")\n", " num_load_btn_5 = gr.Number(\n", " label=\"# Load Upload File with Invalid file_types\", value=0\n", " )\n", " file_component_invalid.upload(\n", " lambda s, n: (s, n + 1),\n", " [file_component_invalid, num_load_btn_5],\n", " [output_file_5, num_load_btn_5],\n", " )\n", " with gr.Row():\n", " with gr.Column():\n", " del_file_input = gr.File(label=\"Delete File\", file_count=\"multiple\")\n", " with gr.Column():\n", " del_file_data = gr.Textbox(label=\"Delete file data\")\n", " num_load_btn_6 = gr.Number(label=\"# Deleted File\", value=0)\n", " del_file_input.delete(\n", " delete_file,\n", " [num_load_btn_6],\n", " [del_file_data, num_load_btn_6],\n", " )\n", " # f = gr.File(label=\"Upload many File\", file_count=\"multiple\")\n", " # # f.delete(delete_file)\n", " # f.delete(delete_file, inputs=None, outputs=None)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -54,7 +54,7 @@ with gr.Blocks() as demo:
|
||||
)
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
file_component_pdf = gr.File(label="Upload PDF File", file_types=["pdf"])
|
||||
file_component_pdf = gr.File(label="Upload PDF File", file_types=[".pdf"])
|
||||
with gr.Column():
|
||||
output_file_4 = gr.File(label="Upload PDF File Output")
|
||||
num_load_btn_4 = gr.Number(label="# Load Upload PDF File", value=0)
|
||||
|
@ -1222,7 +1222,7 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
|
||||
original_mapping[0] = root_block = Context.root_block or blocks
|
||||
|
||||
if "layout" in config:
|
||||
iterate_over_children(config["layout"]["children"]) #
|
||||
iterate_over_children(config["layout"]["children"])
|
||||
|
||||
first_dependency = None
|
||||
|
||||
|
@ -16,6 +16,7 @@ from gradio import processing_utils
|
||||
from gradio.components.base import Component
|
||||
from gradio.data_classes import FileData, ListFiles
|
||||
from gradio.events import Events
|
||||
from gradio.exceptions import Error
|
||||
from gradio.utils import NamedString
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -27,7 +28,7 @@ class File(Component):
|
||||
"""
|
||||
Creates a file component that allows uploading one or more generic files (when used as an input) or displaying generic files or URLs for download (as output).
|
||||
|
||||
Demo: zip_files, zip_to_json
|
||||
Demo: zip_files, zip_to_json
|
||||
"""
|
||||
|
||||
EVENTS = [Events.change, Events.select, Events.clear, Events.upload, Events.delete]
|
||||
@ -125,6 +126,12 @@ class File(Component):
|
||||
def _process_single_file(self, f: FileData) -> NamedString | bytes:
|
||||
file_name = f.path
|
||||
if self.type == "filepath":
|
||||
if self.file_types and not client_utils.is_valid_file(
|
||||
file_name, self.file_types
|
||||
):
|
||||
raise Error(
|
||||
f"Invalid file type. Please upload a file that is one of these formats: {self.file_types}"
|
||||
)
|
||||
file = tempfile.NamedTemporaryFile(delete=False, dir=self.GRADIO_CACHE)
|
||||
file.name = file_name
|
||||
return NamedString(file_name)
|
||||
|
@ -25,6 +25,7 @@ from gradio import processing_utils, utils, wasm_utils
|
||||
from gradio.components.base import Component
|
||||
from gradio.data_classes import FileData, GradioModel, GradioRootModel
|
||||
from gradio.events import Events
|
||||
from gradio.exceptions import Error
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gradio.components import Timer
|
||||
@ -101,7 +102,7 @@ class Gallery(Component):
|
||||
Parameters:
|
||||
value: List of images or videos to display in the gallery by default. If callable, the function will be called whenever the app loads to set the initial value of the component.
|
||||
format: Format to save images before they are returned to the frontend, such as 'jpeg' or 'png'. This parameter only applies to images that are returned from the prediction function as numpy arrays or PIL Images. The format should be supported by the PIL library.
|
||||
file_types: List of file extensions or types of files to be uploaded (e.g. ['image', 'video']), when this is used as an input component. "image" allows only image files to be uploaded, "video" allows only video files to be uploaded, ".mp4" allows only mp4 files to be uploaded, etc. If None, any image and video files types are allowed.
|
||||
file_types: List of file extensions or types of files to be uploaded (e.g. ['image', '.mp4']), when this is used as an input component. "image" allows only image files to be uploaded, "video" allows only video files to be uploaded, ".mp4" allows only mp4 files to be uploaded, etc. If None, any image and video files types are allowed.
|
||||
label: The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.
|
||||
every: Continously calls `value` to recalculate it if `value` is a function (has no effect otherwise). Can provide a Timer whose tick resets `value`, or a float that provides the regular interval for the reset Timer.
|
||||
inputs: Components that are used as inputs to calculate `value` if `value` is a function (has no effect otherwise). `value` is recalculated any time the inputs change.
|
||||
@ -184,12 +185,23 @@ class Gallery(Component):
|
||||
return None
|
||||
data = []
|
||||
for gallery_element in payload.root:
|
||||
media = (
|
||||
gallery_element.video.path
|
||||
if (type(gallery_element) is GalleryVideo)
|
||||
else self.convert_to_type(gallery_element.image.path, self.type) # type: ignore
|
||||
)
|
||||
data.append((media, gallery_element.caption))
|
||||
if isinstance(gallery_element, GalleryVideo):
|
||||
file_path = gallery_element.video.path
|
||||
else:
|
||||
file_path = gallery_element.image.path
|
||||
if self.file_types and not client_utils.is_valid_file(
|
||||
file_path, self.file_types
|
||||
):
|
||||
raise Error(
|
||||
f"Invalid file type. Please upload a file that is one of these formats: {self.file_types}"
|
||||
)
|
||||
else:
|
||||
media = (
|
||||
gallery_element.video.path
|
||||
if (type(gallery_element) is GalleryVideo)
|
||||
else self.convert_to_type(gallery_element.image.path, self.type) # type: ignore
|
||||
)
|
||||
data.append((media, gallery_element.caption))
|
||||
return data
|
||||
|
||||
def postprocess(
|
||||
|
@ -14,6 +14,7 @@ from typing_extensions import NotRequired
|
||||
from gradio.components.base import Component, FormComponent
|
||||
from gradio.data_classes import FileData, GradioModel
|
||||
from gradio.events import Events
|
||||
from gradio.exceptions import Error
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gradio.components import Timer
|
||||
@ -159,6 +160,12 @@ class MultimodalTextbox(FormComponent):
|
||||
"""
|
||||
if payload is None:
|
||||
return None
|
||||
if self.file_types is not None:
|
||||
for f in payload.files:
|
||||
if not client_utils.is_valid_file(f.path, self.file_types):
|
||||
raise Error(
|
||||
f"Invalid file type: {f.mime_type}. Please upload a file that is one of these formats: {self.file_types}"
|
||||
)
|
||||
return {
|
||||
"text": payload.text,
|
||||
"files": [f.path for f in payload.files],
|
||||
|
@ -16,6 +16,7 @@ from gradio import processing_utils
|
||||
from gradio.components.base import Component
|
||||
from gradio.data_classes import FileData, ListFiles
|
||||
from gradio.events import Events
|
||||
from gradio.exceptions import Error
|
||||
from gradio.utils import NamedString
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -146,6 +147,12 @@ class UploadButton(Component):
|
||||
def _process_single_file(self, f: FileData) -> bytes | NamedString:
|
||||
file_name = f.path
|
||||
if self.type == "filepath":
|
||||
if self.file_types and not client_utils.is_valid_file(
|
||||
file_name, self.file_types
|
||||
):
|
||||
raise Error(
|
||||
f"Invalid file type. Please upload a file that is one of these formats: {self.file_types}"
|
||||
)
|
||||
file = tempfile.NamedTemporaryFile(delete=False, dir=self.GRADIO_CACHE)
|
||||
file.name = file_name
|
||||
return NamedString(file_name)
|
||||
@ -170,7 +177,6 @@ class UploadButton(Component):
|
||||
"""
|
||||
if payload is None:
|
||||
return None
|
||||
|
||||
if self.file_count == "single":
|
||||
if isinstance(payload, ListFiles):
|
||||
return self._process_single_file(payload[0])
|
||||
|
Loading…
Reference in New Issue
Block a user