mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-12 12:40:29 +08:00
Support gr.load()
-ing Gradio apps with Blocks.load()
events (#10324)
* changes * add changeset * changes * changes * add changeset * changes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
parent
354341826a
commit
343503d62e
5
.changeset/tall-geese-hammer.md
Normal file
5
.changeset/tall-geese-hammer.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"gradio": patch
|
||||
---
|
||||
|
||||
fix:Support `gr.load()`-ing Gradio apps with `Blocks.load()` events
|
@ -40,7 +40,7 @@ from gradio import (
|
||||
utils,
|
||||
wasm_utils,
|
||||
)
|
||||
from gradio.blocks_events import BlocksEvents, BlocksMeta
|
||||
from gradio.blocks_events import BLOCKS_EVENTS, BlocksEvents, BlocksMeta
|
||||
from gradio.context import (
|
||||
Context,
|
||||
LocalContext,
|
||||
@ -1315,21 +1315,14 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
|
||||
)
|
||||
dependency["no_target"] = True
|
||||
else:
|
||||
targets = [
|
||||
getattr(
|
||||
original_mapping[
|
||||
target if isinstance(target, int) else target[0]
|
||||
],
|
||||
trigger if isinstance(target, int) else target[1],
|
||||
)
|
||||
for target in _targets
|
||||
]
|
||||
targets = [
|
||||
EventListenerMethod(
|
||||
t.__self__ if t.has_trigger else None,
|
||||
t.event_name, # type: ignore
|
||||
)
|
||||
for t in targets
|
||||
for t in Blocks.get_event_targets(
|
||||
original_mapping, _targets, trigger
|
||||
)
|
||||
]
|
||||
dependency = root_block.default_config.set_event_trigger(
|
||||
targets=targets, fn=fn, **dependency
|
||||
@ -1433,6 +1426,11 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
|
||||
]
|
||||
for dependency in self.fns.values():
|
||||
dependency._id += dependency_offset
|
||||
# Any event -- e.g. Blocks.load() -- that is triggered by this Blocks
|
||||
# should now be triggered by the root Blocks instead.
|
||||
for target in dependency.targets:
|
||||
if target[0] == self._id:
|
||||
target = (Context.root_block._id, target[1])
|
||||
api_name = dependency.api_name
|
||||
if isinstance(api_name, str):
|
||||
api_name_ = utils.append_unique_suffix(
|
||||
@ -3006,3 +3004,29 @@ Received inputs:
|
||||
api_info["named_endpoints"][f"/{fn.api_name}"] = dependency_info
|
||||
|
||||
return api_info
|
||||
|
||||
@staticmethod
|
||||
def get_event_targets(
|
||||
original_mapping: dict[int, Block], _targets: list, trigger: str
|
||||
) -> list:
|
||||
target_events = []
|
||||
for target in _targets:
|
||||
# If target is just an integer (old format), use it directly with the trigger
|
||||
# Otherwise target is a tuple and we use its components
|
||||
target_id = target if isinstance(target, int) else target[0]
|
||||
event_name = trigger if isinstance(target, int) else target[1]
|
||||
block = original_mapping.get(target_id)
|
||||
# Blocks events are a special case because they are not stored in the blocks list in the config
|
||||
if block is None:
|
||||
if event_name in [
|
||||
event.event_name if isinstance(event, EventListener) else event
|
||||
for event in BLOCKS_EVENTS
|
||||
]:
|
||||
block = Context.root_block
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Cannot find Block with id: {target_id} but is present as a target in the config"
|
||||
)
|
||||
event = getattr(block, event_name)
|
||||
target_events.append(event)
|
||||
return target_events
|
||||
|
@ -518,7 +518,7 @@ def safe_deepcopy(obj: Any) -> Any:
|
||||
|
||||
|
||||
def assert_configs_are_equivalent_besides_ids(
|
||||
config1: dict, config2: dict, root_keys: tuple = ("mode",)
|
||||
config1: BlocksConfigDict, config2: BlocksConfigDict, root_keys: tuple = ("mode",)
|
||||
):
|
||||
"""Allows you to test if two different Blocks configs produce the same demo.
|
||||
|
||||
@ -563,20 +563,31 @@ def assert_configs_are_equivalent_besides_ids(
|
||||
if "children" in child1 or "children" in child2:
|
||||
same_children_recursive(child1["children"], child2["children"])
|
||||
|
||||
children1 = config1["layout"]["children"]
|
||||
children2 = config2["layout"]["children"]
|
||||
same_children_recursive(children1, children2)
|
||||
if "layout" in config1:
|
||||
if "layout" not in config2:
|
||||
raise ValueError(
|
||||
"The first config has a layout key, but the second does not"
|
||||
)
|
||||
children1 = config1["layout"]["children"]
|
||||
children2 = config2["layout"]["children"]
|
||||
same_children_recursive(children1, children2)
|
||||
|
||||
for d1, d2 in zip(config1["dependencies"], config2["dependencies"], strict=False):
|
||||
for t1, t2 in zip(d1.pop("targets"), d2.pop("targets"), strict=False):
|
||||
assert_same_components(t1[0], t2[0])
|
||||
for i1, i2 in zip(d1.pop("inputs"), d2.pop("inputs"), strict=False):
|
||||
assert_same_components(i1, i2)
|
||||
for o1, o2 in zip(d1.pop("outputs"), d2.pop("outputs"), strict=False):
|
||||
assert_same_components(o1, o2)
|
||||
|
||||
if d1 != d2:
|
||||
raise ValueError(f"{d1} does not match {d2}")
|
||||
if "dependencies" in config1:
|
||||
if "dependencies" not in config2:
|
||||
raise ValueError(
|
||||
"The first config has a dependencies key, but the second does not"
|
||||
)
|
||||
for d1, d2 in zip(
|
||||
config1["dependencies"], config2["dependencies"], strict=False
|
||||
):
|
||||
for t1, t2 in zip(d1.pop("targets"), d2.pop("targets"), strict=False):
|
||||
assert_same_components(t1[0], t2[0])
|
||||
for i1, i2 in zip(d1.pop("inputs"), d2.pop("inputs"), strict=False):
|
||||
assert_same_components(i1, i2)
|
||||
for o1, o2 in zip(d1.pop("outputs"), d2.pop("outputs"), strict=False):
|
||||
assert_same_components(o1, o2)
|
||||
if d1 != d2:
|
||||
raise ValueError(f"{d1} does not match {d2}")
|
||||
|
||||
return True
|
||||
|
||||
|
@ -92,7 +92,20 @@ class TestBlocksMethods:
|
||||
for component in config1["components"]:
|
||||
component["props"]["proxy_url"] = f"{fake_url}/"
|
||||
config2 = demo2.get_config_file()
|
||||
assert assert_configs_are_equivalent_besides_ids(config1, config2) # type: ignore
|
||||
assert assert_configs_are_equivalent_besides_ids(config1, config2)
|
||||
|
||||
def test_load_from_config_with_blocks_events(self):
|
||||
fake_url = "https://fake.hf.space"
|
||||
|
||||
def fn():
|
||||
return "Hello"
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
t = gr.Textbox()
|
||||
demo.load(fn, None, t)
|
||||
|
||||
config = demo.get_config_file()
|
||||
gr.Blocks.from_config(config, [fn], fake_url) # Should not raise
|
||||
|
||||
def test_partial_fn_in_config(self):
|
||||
def greet(name, formatter):
|
||||
|
Loading…
x
Reference in New Issue
Block a user