From 7b3ad308913b6df28b0cdd9d4bae15e61d326124 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Fri, 21 Jan 2022 20:37:11 -0600 Subject: [PATCH 01/10] added /file route to serve examples --- gradio/app.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/gradio/app.py b/gradio/app.py index 080202955d..c9c86508d5 100644 --- a/gradio/app.py +++ b/gradio/app.py @@ -3,6 +3,7 @@ from __future__ import annotations import inspect +import io import os import posixpath import secrets @@ -20,7 +21,7 @@ from fastapi.security import OAuth2PasswordRequestForm from fastapi.templating import Jinja2Templates from starlette.responses import RedirectResponse -from gradio import queueing, utils +from gradio import encryptor, queueing, utils from gradio.process_examples import load_from_cache, process_example STATIC_TEMPLATE_LIB = pkg_resources.resource_filename("gradio", "templates/") @@ -126,6 +127,21 @@ def static_resource(path: str): raise HTTPException(status_code=404, detail="Static file not found") +@app.get("/file/{path:path}", dependencies=[Depends(login_check)]) +def file(path): + if app.interface.encrypt and isinstance( + app.interface.examples, str) and path.startswith( + app.interface.examples): + with open(safe_join(app.cwd, path), "rb") as encrypted_file: + encrypted_data = encrypted_file.read() + file_data = encryptor.decrypt( + app.interface.encryption_key, encrypted_data) + return FileResponse( + io.BytesIO(file_data), attachment_filename=os.path.basename(path)) + else: + return FileResponse(safe_join(app.cwd, path)) + + @app.get("/api", response_class=HTMLResponse) # Needed for Spaces @app.get("/api/", response_class=HTMLResponse) def api_docs(request: Request): From 452d26b88ca5dfa596c50c1b09ca621b689e1f07 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Fri, 21 Jan 2022 20:39:46 -0600 Subject: [PATCH 02/10] updated PyPi version to 2.7.5.1 --- gradio.egg-info/PKG-INFO | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradio.egg-info/PKG-INFO b/gradio.egg-info/PKG-INFO index 3a50a66de8..f59845e54a 100644 --- a/gradio.egg-info/PKG-INFO +++ b/gradio.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: gradio -Version: 2.7.5 +Version: 2.7.5.1 Summary: Python library for easily interacting with trained machine learning models Home-page: https://github.com/gradio-app/gradio-UI Author: Abubakar Abid, Ali Abid, Ali Abdalla, Dawood Khan, Ahsen Khaliq diff --git a/setup.py b/setup.py index 02dcaf4273..218dfa1922 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ except ImportError: setup( name="gradio", - version="2.7.5", + version="2.7.5.1", include_package_data=True, description="Python library for easily interacting with trained machine learning models", author="Abubakar Abid, Ali Abid, Ali Abdalla, Dawood Khan, Ahsen Khaliq", From 15791b1d1d27c45d9124318e3e74b3b95e15c0f1 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 20:17:48 -0500 Subject: [PATCH 03/10] fixed queueing with examples --- gradio/app.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gradio/app.py b/gradio/app.py index c9c86508d5..b1b793569f 100644 --- a/gradio/app.py +++ b/gradio/app.py @@ -260,9 +260,8 @@ async def interpret(request: Request): @app.post("/api/queue/push/", dependencies=[Depends(login_check)]) async def queue_push(request: Request): body = await request.json() - data = body["data"] action = body["action"] - job_hash, queue_position = queueing.push({"data": data}, action) + job_hash, queue_position = queueing.push(body, action) return {"hash": job_hash, "queue_position": queue_position} From a40700dae6c73653e1edbfcd9c13ff7dba7b7403 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 20:25:06 -0500 Subject: [PATCH 04/10] minor cleanups --- gradio/interface.py | 4 ++-- gradio/notebook.py | 0 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 gradio/notebook.py diff --git a/gradio/interface.py b/gradio/interface.py index 75d8d1c3fa..2c7e9c78bd 100644 --- a/gradio/interface.py +++ b/gradio/interface.py @@ -244,8 +244,8 @@ class Interface: self.description = description if article is not None: article = utils.readme_to_html(article) - article = markdown2.markdown(article, extras=["fenced-code-blocks"]) - + article = markdown2.markdown( + article, extras=["fenced-code-blocks"]) self.article = article self.thumbnail = thumbnail diff --git a/gradio/notebook.py b/gradio/notebook.py deleted file mode 100644 index e69de29bb2..0000000000 From 75a496a2418a69ff28544a8abbadc1280e632df4 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 20:29:00 -0500 Subject: [PATCH 05/10] added typing to component.py --- gradio/component.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/gradio/component.py b/gradio/component.py index 647c112ee7..936a21e10c 100644 --- a/gradio/component.py +++ b/gradio/component.py @@ -1,5 +1,6 @@ import os import shutil +from typing import Any, Dict from gradio import processing_utils @@ -32,7 +33,13 @@ class Component: """ return {} - def save_flagged(self, dir, label, data, encryption_key): + def save_flagged( + self, + dir: str, + label: str, + data: Any, + encryption_key: bool + ) -> Any: """ Saves flagged data from component """ @@ -44,7 +51,16 @@ class Component: """ return data - def save_flagged_file(self, dir, label, data, encryption_key): + def save_flagged_file( + self, + dir: str, + label: str, + data: Any, + encryption_key: bool + ) -> str: + """ + Saved flagged data (e.g. image or audio) as a file and returns filepath + """ if data is None: return None file = processing_utils.decode_base64_to_file(data, encryption_key) @@ -64,7 +80,15 @@ class Component: shutil.move(old_file_name, os.path.join(dir, label, new_file_name)) return label + "/" + new_file_name - def restore_flagged_file(self, dir, file, encryption_key): + def restore_flagged_file( + self, + dir: str, + file: str, + encryption_key: bool, + ) -> Dict[str, Any]: + """ + Loads flagged data from file and returns it + """ data = processing_utils.encode_file_to_base64( os.path.join(dir, file), encryption_key=encryption_key ) From c1c71663a3fa377633cd0a38fd6bef80efa43ba2 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 20:40:06 -0500 Subject: [PATCH 06/10] added typing to encryptor --- gradio/encryptor.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/gradio/encryptor.py b/gradio/encryptor.py index 6ec118a141..58ab17cd01 100644 --- a/gradio/encryptor.py +++ b/gradio/encryptor.py @@ -3,12 +3,19 @@ from Crypto.Cipher import AES from Crypto.Hash import SHA256 -def get_key(password): +def get_key( + password: str +) -> bytes: + """Generates an encryption key based on the password provided.""" key = SHA256.new(password.encode()).digest() return key -def encrypt(key, source): +def encrypt( + key: bytes, + source: bytes +) -> bytes: + """Encrypts source data using the provided encryption key""" IV = Random.new().read(AES.block_size) # generate IV encryptor = AES.new(key, AES.MODE_CBC, IV) padding = AES.block_size - len(source) % AES.block_size # calculate needed padding @@ -17,7 +24,10 @@ def encrypt(key, source): return data -def decrypt(key, source): +def decrypt( + key: bytes, + source: bytes +) -> bytes: IV = source[: AES.block_size] # extract the IV from the beginning decryptor = AES.new(key, AES.MODE_CBC, IV) data = decryptor.decrypt(source[AES.block_size :]) # decrypt From b16cd78f40f02756db9d3132c28e00521f115671 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 22:47:18 -0600 Subject: [PATCH 07/10] added tests for encryptor.py --- gradio/encryptor.py | 1 + test/test_encryptor.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/test_encryptor.py diff --git a/gradio/encryptor.py b/gradio/encryptor.py index 58ab17cd01..97f6c8a592 100644 --- a/gradio/encryptor.py +++ b/gradio/encryptor.py @@ -19,6 +19,7 @@ def encrypt( IV = Random.new().read(AES.block_size) # generate IV encryptor = AES.new(key, AES.MODE_CBC, IV) padding = AES.block_size - len(source) % AES.block_size # calculate needed padding + print(type(source), type(padding)) source += bytes([padding]) * padding # Python 2.x: source += chr(padding) * padding data = IV + encryptor.encrypt(source) # store the IV at the beginning and encrypt return data diff --git a/test/test_encryptor.py b/test/test_encryptor.py new file mode 100644 index 0000000000..0c20ee8594 --- /dev/null +++ b/test/test_encryptor.py @@ -0,0 +1,33 @@ +import os +import unittest + +from gradio import encryptor, processing_utils +from gradio.test_data import BASE64_IMAGE + + +os.environ["GRADIO_ANALYTICS_ENABLED"] = "False" + + +class TestKeyGenerator(unittest.TestCase): + def test_same_pass(self): + key1 = encryptor.get_key("test") + key2 = encryptor.get_key("test") + self.assertEquals(key1, key2) + + def test_diff_pass(self): + key1 = encryptor.get_key("test") + key2 = encryptor.get_key("diff_test") + self.assertNotEquals(key1, key2) + + +class TestEncryptorDecryptor(unittest.TestCase): + def test_same_pass(self): + key = encryptor.get_key("test") + data, _ = processing_utils.decode_base64_to_binary(BASE64_IMAGE) + encrypted_data = encryptor.encrypt(key, data) + decrypted_data = encryptor.decrypt(key, encrypted_data) + self.assertEquals(data, decrypted_data) + + +if __name__ == "__main__": + unittest.main() From f6341be7c7fc611c3f7f14e064ebc11d672ff5d6 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 22:54:48 -0600 Subject: [PATCH 08/10] flagging --- gradio/encryptor.py | 1 - gradio/flagging.py | 3 +-- test/test_flagging.py | 6 ++++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gradio/encryptor.py b/gradio/encryptor.py index 97f6c8a592..58ab17cd01 100644 --- a/gradio/encryptor.py +++ b/gradio/encryptor.py @@ -19,7 +19,6 @@ def encrypt( IV = Random.new().read(AES.block_size) # generate IV encryptor = AES.new(key, AES.MODE_CBC, IV) padding = AES.block_size - len(source) % AES.block_size # calculate needed padding - print(type(source), type(padding)) source += bytes([padding]) * padding # Python 2.x: source += chr(padding) * padding data = IV + encryptor.encrypt(source) # store the IV at the beginning and encrypt return data diff --git a/gradio/flagging.py b/gradio/flagging.py index 106bcf9f80..14d5ee0438 100644 --- a/gradio/flagging.py +++ b/gradio/flagging.py @@ -109,9 +109,8 @@ class SimpleCSVLogger(FlaggingCallback): class CSVLogger(FlaggingCallback): """ The default implementation of the FlaggingCallback abstract class. - Logs the input and output data to a CSV file. + Logs the input and output data to a CSV file. Supports encryption. """ - def setup(self, flagging_dir: str): self.flagging_dir = flagging_dir os.makedirs(flagging_dir, exist_ok=True) diff --git a/test/test_flagging.py b/test/test_flagging.py index d967a31818..d78cccd10f 100644 --- a/test/test_flagging.py +++ b/test/test_flagging.py @@ -6,7 +6,7 @@ import gradio as gr from gradio import flagging -class TestFlagging(unittest.TestCase): +class TestDefaultFlagging(unittest.TestCase): def test_default_flagging_handler(self): with tempfile.TemporaryDirectory() as tmpdirname: io = gr.Interface(lambda x: x, "text", "text", flagging_dir=tmpdirname) @@ -17,6 +17,8 @@ class TestFlagging(unittest.TestCase): self.assertEqual(row_count, 2) # 3 rows written including header io.close() + +class TestSimpleFlagging(unittest.TestCase): def test_simple_csv_flagging_handler(self): with tempfile.TemporaryDirectory() as tmpdirname: io = gr.Interface( @@ -33,6 +35,6 @@ class TestFlagging(unittest.TestCase): self.assertEqual(row_count, 1) # no header io.close() - + if __name__ == "__main__": unittest.main() From b1a582c6c502a19407b7562448efcb5a5b814257 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 22:55:13 -0600 Subject: [PATCH 09/10] unused improt --- test/test_flagging.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_flagging.py b/test/test_flagging.py index d78cccd10f..1533949c0f 100644 --- a/test/test_flagging.py +++ b/test/test_flagging.py @@ -1,6 +1,5 @@ import tempfile import unittest -import unittest.mock as mock import gradio as gr from gradio import flagging From 11abd5520a28dec70f8082e961d71f119d6b03e9 Mon Sep 17 00:00:00 2001 From: Abubakar Abid Date: Sun, 23 Jan 2022 23:09:11 -0600 Subject: [PATCH 10/10] updated PyPi version to 2.7.5.2 --- gradio.egg-info/PKG-INFO | 2 +- gradio/version.txt | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradio.egg-info/PKG-INFO b/gradio.egg-info/PKG-INFO index f59845e54a..2f81128628 100644 --- a/gradio.egg-info/PKG-INFO +++ b/gradio.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: gradio -Version: 2.7.5.1 +Version: 2.7.5.2 Summary: Python library for easily interacting with trained machine learning models Home-page: https://github.com/gradio-app/gradio-UI Author: Abubakar Abid, Ali Abid, Ali Abdalla, Dawood Khan, Ahsen Khaliq diff --git a/gradio/version.txt b/gradio/version.txt index 460b6fd404..cc14ca0b0b 100644 --- a/gradio/version.txt +++ b/gradio/version.txt @@ -1 +1 @@ -2.7.5 \ No newline at end of file +2.7.5.2 \ No newline at end of file diff --git a/setup.py b/setup.py index 218dfa1922..c257f9ced0 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ except ImportError: setup( name="gradio", - version="2.7.5.1", + version="2.7.5.2", include_package_data=True, description="Python library for easily interacting with trained machine learning models", author="Abubakar Abid, Ali Abid, Ali Abdalla, Dawood Khan, Ahsen Khaliq",