Fix for deepcopy errors when running the replica-related logic on Spaces (#5722)

* fix changelogs

* pass

* add changeset

* test

* config

* change

* fixes

* route utils

* add changeset

* add changeset

* add lock

* print

* route url

* replicas

* replicas

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
Abubakar Abid 2023-09-28 10:59:31 -07:00 committed by GitHub
parent 96c4b97c74
commit dba651904c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 19 deletions

View File

@ -0,0 +1,5 @@
---
"gradio": patch
---
feat:Fix for deepcopy errors when running the replica-related logic on Spaces

View File

@ -1,6 +1,5 @@
from __future__ import annotations
import copy
import json
from typing import TYPE_CHECKING, Optional, Union
@ -248,11 +247,18 @@ async def call_process_api(
return output
def set_replica_url_in_config(config: dict, replica_url: str) -> dict:
def set_replica_url_in_config(
config: dict, replica_url: str, all_replica_urls: set[str]
) -> None:
"""
If the Gradio app is running on Hugging Face Spaces and the machine has multiple replicas,
we pass in the direct URL to the replica so that we have the fully resolved path to any files
on that machine. This direct URL can be shared with other users and the path will still work.
Parameters:
config: The config dictionary to modify.
replica_url: The direct URL to the replica.
all_replica_urls: The direct URLs to the other replicas. These should be replaced with the replica_url.
"""
parsed_url = httpx.URL(replica_url)
stripped_url = parsed_url.copy_with(query=None)
@ -260,11 +266,9 @@ def set_replica_url_in_config(config: dict, replica_url: str) -> dict:
if not stripped_url.endswith("/"):
stripped_url += "/"
config_ = copy.deepcopy(config)
for component in config_["components"]:
if (
component.get("props") is not None
and component["props"].get("root_url") is None
):
component["props"]["root_url"] = stripped_url
return config_
for component in config["components"]:
if component.get("props") is not None:
root_url = component["props"].get("root_url")
# Don't replace the root_url if it's loaded from a different Space
if root_url is None or root_url in all_replica_urls:
component["props"]["root_url"] = stripped_url

View File

@ -303,7 +303,7 @@ class App(FastAPI):
@app.head("/", response_class=HTMLResponse)
@app.get("/", response_class=HTMLResponse)
def main(request: fastapi.Request, user: str = Depends(get_current_user)):
async def main(request: fastapi.Request, user: str = Depends(get_current_user)):
mimetypes.add_type("application/javascript", ".js")
blocks = app.get_blocks()
root_path = request.scope.get("root_path", "")
@ -317,7 +317,8 @@ class App(FastAPI):
replica_url = request.headers.get("X-Direct-Url")
if utils.get_space() and replica_url:
app.replica_urls.add(replica_url)
config = set_replica_url_in_config(config, replica_url)
async with app.lock:
set_replica_url_in_config(config, replica_url, app.replica_urls)
else:
config = {
"auth_required": True,
@ -354,7 +355,7 @@ class App(FastAPI):
@app.get("/config/", dependencies=[Depends(login_check)])
@app.get("/config", dependencies=[Depends(login_check)])
def get_config(request: fastapi.Request):
async def get_config(request: fastapi.Request):
config = app.get_blocks().config
# Handles the case where the app is running on Hugging Face Spaces with
@ -362,7 +363,8 @@ class App(FastAPI):
replica_url = request.headers.get("X-Direct-Url")
if utils.get_space() and replica_url:
app.replica_urls.add(replica_url)
config = set_replica_url_in_config(config, replica_url)
async with app.lock:
set_replica_url_in_config(config, replica_url, app.replica_urls)
root_path = request.scope.get("root_path", "")
config["root"] = root_path

View File

@ -3,24 +3,33 @@ from gradio.route_utils import set_replica_url_in_config
def test_set_replica_url():
config = {
"components": [{"props": {}}, {"props": {"root_url": "existing_url/"}}, {}]
"components": [
{"props": {}},
{"props": {"root_url": "existing_url/"}},
{"props": {"root_url": "different_url/"}},
{},
]
}
replica_url = "https://abidlabs-test-client-replica--fttzk.hf.space?__theme=light"
config = set_replica_url_in_config(config, replica_url)
set_replica_url_in_config(config, replica_url, {"existing_url/"})
assert (
config["components"][0]["props"]["root_url"]
== "https://abidlabs-test-client-replica--fttzk.hf.space/"
)
assert config["components"][1]["props"]["root_url"] == "existing_url/"
assert "props" not in config["components"][2]
assert (
config["components"][1]["props"]["root_url"]
== "https://abidlabs-test-client-replica--fttzk.hf.space/"
)
assert config["components"][2]["props"]["root_url"] == "different_url/"
assert "props" not in config["components"][3]
def test_url_without_trailing_slash():
config = {"components": [{"props": {}}]}
replica_url = "https://abidlabs-test-client-replica--fttzk.hf.space"
config = set_replica_url_in_config(config, replica_url)
set_replica_url_in_config(config, replica_url, set())
assert (
config["components"][0]["props"]["root_url"]
== "https://abidlabs-test-client-replica--fttzk.hf.space/"