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:
Dawood Khan 2024-10-01 13:12:47 -04:00 committed by GitHub
parent c307a0c9b8
commit 7065e11e46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 82 additions and 12 deletions

View File

@ -0,0 +1,6 @@
---
"gradio": patch
"gradio_client": patch
---
fix:Check for `file_types` parameter in the backend

View File

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

View File

@ -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",
[

View File

@ -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}

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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],

View File

@ -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])