from __future__ import annotations import importlib import sys from pathlib import Path from types import ModuleType ROOT = Path(__file__).resolve().parents[1] for candidate in (ROOT, ROOT / "src"): if str(candidate) not in sys.path: sys.path.insert(0, str(candidate)) class _DummyComponent: def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.bindings: list[tuple[str, tuple[object, ...], dict[str, object]]] = [] def click(self, *args, **kwargs): self.bindings.append(("click", args, kwargs)) return self def change(self, *args, **kwargs): self.bindings.append(("change", args, kwargs)) return self class _DummyContext(_DummyComponent): def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def _install_fake_gradio(monkeypatch): blocks: list[object] = [] fake = ModuleType("gradio") class DummyBlocks(_DummyContext): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.launch_args: tuple[object, ...] | None = None self.launch_kwargs: dict[str, object] | None = None self.load_args: tuple[object, ...] | None = None self.load_kwargs: dict[str, object] | None = None blocks.append(self) def queue(self, *args, **kwargs): self.queue_args = args self.queue_kwargs = kwargs return self def launch(self, *args, **kwargs): self.launch_args = args self.launch_kwargs = kwargs return self def load(self, *args, **kwargs): self.load_args = args self.load_kwargs = kwargs return self def make_component(name: str): def factory(*args, **kwargs): return _DummyComponent(name, *args, **kwargs) return factory def make_context(name: str): def factory(*args, **kwargs): return _DummyContext(name, *args, **kwargs) return factory fake.Blocks = DummyBlocks for name in ["Markdown", "Row", "Button", "JSON", "Tabs", "Tab", "Column", "Textbox", "Dropdown", "Dataframe", "Image", "Number", "Code", "Gallery", "File", "State"]: factory = make_context(name) if name in {"Row", "Tabs", "Tab", "Column"} else make_component(name) setattr(fake, name, factory) fake.update = lambda **kwargs: kwargs monkeypatch.setitem(sys.modules, "gradio", fake) return blocks def _assert_theme_wired(blocks: list[object], expected_css: Path) -> None: assert blocks, "expected a Gradio Blocks instance to be created" constructor_kwargs = getattr(blocks[-1], "kwargs", None) assert constructor_kwargs is not None, "expected Blocks(...) to capture constructor kwargs" assert Path(constructor_kwargs["css_paths"]).resolve() == expected_css.resolve() launch_kwargs = getattr(blocks[-1], "launch_kwargs", None) assert launch_kwargs is not None, "expected launch() to be called" assert "css_paths" not in launch_kwargs css = expected_css.read_text(encoding="utf-8") assert ".gradio-container" in css assert "Playfair Display" in css assert "fdf6e3" in css.lower() assert "SFMono-Regular" in css def test_root_app_uses_terminal_inspired_css(monkeypatch) -> None: blocks = _install_fake_gradio(monkeypatch) sys.modules.pop("app", None) sys.modules.pop("apps.p5_memory_quilt.app", None) app = importlib.import_module("app") result = app.main([]) assert result == 0 _assert_theme_wired(blocks, ROOT / "assets" / "theme.css")