mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-11 11:19:58 +08:00
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:
parent
96c4b97c74
commit
dba651904c
5
.changeset/true-candles-pay.md
Normal file
5
.changeset/true-candles-pay.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"gradio": patch
|
||||
---
|
||||
|
||||
feat:Fix for deepcopy errors when running the replica-related logic on Spaces
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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/"
|
||||
|
Loading…
Reference in New Issue
Block a user