2023-03-19 11:15:02 +08:00
|
|
|
import tempfile
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
import huggingface_hub
|
|
|
|
import pytest
|
|
|
|
from huggingface_hub.hf_api import SpaceInfo
|
|
|
|
|
|
|
|
import gradio as gr
|
|
|
|
from gradio.themes.utils import ThemeAsset, get_matching_version, get_theme_assets
|
|
|
|
|
|
|
|
versions = [
|
|
|
|
"0.1.0",
|
|
|
|
"0.1.1",
|
|
|
|
"0.1.2",
|
|
|
|
"0.1.3",
|
|
|
|
"0.4.4",
|
|
|
|
"0.5.0",
|
|
|
|
"0.7.0",
|
|
|
|
"0.9.2",
|
|
|
|
"0.9.3",
|
|
|
|
"0.9.4",
|
|
|
|
"0.9.5",
|
|
|
|
"0.9.6",
|
|
|
|
"0.9.7",
|
|
|
|
"0.9.8",
|
|
|
|
"2.2.0",
|
|
|
|
"2.2.1",
|
|
|
|
"2.2.10",
|
|
|
|
"2.2.11",
|
|
|
|
"2.2.12",
|
|
|
|
"2.2.13",
|
|
|
|
"2.2.14",
|
|
|
|
"2.2.15",
|
|
|
|
"2.2.2",
|
|
|
|
"2.2.3",
|
|
|
|
"2.2.4",
|
|
|
|
"2.2.5",
|
|
|
|
"2.2.6",
|
|
|
|
"2.2.7",
|
|
|
|
"2.2.8",
|
|
|
|
"3.0.1",
|
|
|
|
"3.0.10",
|
|
|
|
"3.0.11",
|
|
|
|
"3.0.12",
|
|
|
|
"3.0.13",
|
|
|
|
"3.0.14",
|
|
|
|
"3.0.15",
|
|
|
|
"3.0.16",
|
|
|
|
"3.0.17",
|
|
|
|
"3.0.18",
|
|
|
|
"3.0.19",
|
|
|
|
"3.0.2",
|
|
|
|
"3.0.20",
|
|
|
|
"3.0.20-dev0",
|
|
|
|
"3.0.21",
|
|
|
|
"3.0.22",
|
|
|
|
"3.0.23",
|
|
|
|
"3.0.23-dev1",
|
|
|
|
"3.0.24",
|
|
|
|
"3.0.25",
|
|
|
|
"3.0.26",
|
|
|
|
"3.0.3",
|
|
|
|
"3.0.4",
|
|
|
|
"3.0.5",
|
|
|
|
"3.0.6",
|
|
|
|
"3.0.7",
|
|
|
|
"3.0.8",
|
|
|
|
"3.0.9",
|
|
|
|
"3.1.0",
|
|
|
|
"3.1.1",
|
|
|
|
"3.1.2",
|
|
|
|
"3.1.3",
|
|
|
|
"3.1.4",
|
|
|
|
"3.1.5",
|
|
|
|
"3.1.6",
|
|
|
|
"3.1.7",
|
|
|
|
"3.10.0",
|
|
|
|
"3.10.1",
|
|
|
|
"3.11.0",
|
|
|
|
"3.12.0",
|
|
|
|
"3.13.0",
|
|
|
|
"3.13.1",
|
|
|
|
"3.13.2",
|
|
|
|
"3.14.0",
|
|
|
|
"3.15.0",
|
|
|
|
"3.16.0",
|
|
|
|
"3.16.1",
|
|
|
|
"3.16.2",
|
|
|
|
"3.17.0",
|
|
|
|
"3.17.1",
|
|
|
|
"3.18.0",
|
|
|
|
"3.18.1",
|
|
|
|
"3.18.1-dev0",
|
|
|
|
"3.18.2-dev0",
|
|
|
|
"3.18.2",
|
|
|
|
"3.19.0",
|
|
|
|
"3.19.1",
|
|
|
|
"3.20.0",
|
|
|
|
"3.20.1",
|
|
|
|
"3.3.1",
|
|
|
|
"3.4.1",
|
|
|
|
"3.8.1",
|
|
|
|
"3.8.2",
|
|
|
|
"3.9.1",
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
assets = [ThemeAsset(f"theme_schema@{version}") for version in versions]
|
|
|
|
|
|
|
|
dracula_gray = gr.themes.colors.Color(
|
|
|
|
*(
|
|
|
|
["#6272a4", "#7280ad", "#818eb6", "#919cbf", "#a1aac8"][::-1]
|
|
|
|
+ ["#586794", "#4e5b83", "#455073", "#3b4462", "#313952", "#272e42"]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
dracula_pink = gr.themes.Color(
|
|
|
|
*(
|
|
|
|
[
|
|
|
|
"#ffd7ee",
|
|
|
|
"#ff79c6",
|
|
|
|
"#ff86cc",
|
|
|
|
"#ff94d1",
|
|
|
|
"#ffa1d7",
|
|
|
|
"#ffafdd",
|
|
|
|
"#ffbce3",
|
|
|
|
"#ffc9e8",
|
|
|
|
][::-1]
|
|
|
|
+ ["#e66db2", "#cc619e", "#b3558b"]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
dracula_gray = gr.themes.colors.Color(
|
|
|
|
*(
|
|
|
|
["#6272a4", "#7280ad", "#818eb6", "#919cbf", "#a1aac8"][::-1]
|
|
|
|
+ ["#586794", "#4e5b83", "#455073", "#3b4462", "#313952", "#272e42"]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
dracula = gr.themes.Base(
|
|
|
|
primary_hue=gr.themes.colors.pink,
|
|
|
|
neutral_hue=dracula_gray,
|
|
|
|
font=gr.themes.GoogleFont("Poppins"),
|
|
|
|
).set(
|
|
|
|
body_background_fill=dracula_gray.c500,
|
|
|
|
color_accent_soft=dracula_gray.c100,
|
2023-06-16 01:51:09 +08:00
|
|
|
error_border_color="#fecaca",
|
|
|
|
error_background_fill="#fee2e2",
|
|
|
|
error_icon_color="#b91c1c",
|
|
|
|
error_icon_color_dark="#ef4444",
|
|
|
|
error_text_color="#ef4444",
|
|
|
|
error_text_color_dark="#ef4444",
|
2023-03-19 11:15:02 +08:00
|
|
|
background_fill_primary=dracula_gray.c500,
|
|
|
|
background_fill_secondary=dracula_gray.c500,
|
|
|
|
block_background_fill=dracula_gray.c300,
|
|
|
|
body_text_color="#f8f8f2",
|
|
|
|
body_text_color_dark="#f8f8f2",
|
|
|
|
body_text_color_subdued="#f8f8f2",
|
|
|
|
block_label_text_color="#f8f8f2",
|
|
|
|
block_label_text_color_dark="#f8f8f2",
|
|
|
|
table_even_background_fill=dracula_gray.c300,
|
|
|
|
border_color_accent=dracula_gray.c200,
|
|
|
|
block_info_text_color="#f8f8f2",
|
|
|
|
block_info_text_color_dark="#f8f8f2",
|
|
|
|
block_title_text_color="#f8f8f2",
|
|
|
|
block_title_text_color_dark="#f8f8f2",
|
|
|
|
checkbox_background_color_selected_dark="#ff79c6",
|
|
|
|
checkbox_background_color_selected="#ff79c6",
|
|
|
|
button_primary_background_fill_dark="#ff79c6",
|
|
|
|
button_primary_background_fill=dracula_pink.c300,
|
|
|
|
button_secondary_text_color="#f8f8f2",
|
|
|
|
slider_color_dark="#ff79c6",
|
|
|
|
slider_color=dracula_pink.c300,
|
|
|
|
panel_background_fill="#31395294",
|
|
|
|
block_background_fill_dark="#31395294",
|
|
|
|
)
|
2023-03-24 05:27:16 +08:00
|
|
|
dracula.name = "gradio/dracula_test"
|
2023-03-19 11:15:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
class TestSemverMatch:
|
|
|
|
def test_simple_equality(self):
|
|
|
|
assert get_matching_version(assets, "3.10.0") == ThemeAsset(
|
|
|
|
"theme_schema@3.10.0"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_empty_expression_returns_latest(self):
|
|
|
|
assert get_matching_version(assets, None) == ThemeAsset("theme_schema@3.20.1")
|
|
|
|
|
|
|
|
def test_range(self):
|
|
|
|
assert get_matching_version(assets, ">=3.10.0,<3.15") == ThemeAsset(
|
|
|
|
"theme_schema@3.14.0"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_wildcard(self):
|
|
|
|
assert get_matching_version(assets, "2.2.*") == ThemeAsset(
|
|
|
|
"theme_schema@2.2.15"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_does_not_exist(self):
|
|
|
|
assert get_matching_version(assets, ">4.0.0") is None
|
|
|
|
|
|
|
|
def test_compatible_release_specifier(self):
|
|
|
|
assert get_matching_version(assets, "~=0.0") == ThemeAsset("theme_schema@0.9.8")
|
|
|
|
|
|
|
|
def test_breaks_ties_against_prerelease(self):
|
|
|
|
assert get_matching_version(assets, ">=3.18,<3.19") == ThemeAsset(
|
|
|
|
"theme_schema@3.18.2"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class TestGetThemeAssets:
|
|
|
|
def test_get_theme_assets(self):
|
|
|
|
space_info = huggingface_hub.hf_api.SpaceInfo(
|
|
|
|
id="freddyaboulton/dracula",
|
|
|
|
siblings=[
|
|
|
|
{
|
|
|
|
"blob_id": None,
|
|
|
|
"lfs": None,
|
|
|
|
"rfilename": "themes/theme_schema@0.1.0.json",
|
|
|
|
"size": None,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"blob_id": None,
|
|
|
|
"lfs": None,
|
|
|
|
"rfilename": "themes/theme_schema@0.1.1.json",
|
|
|
|
"size": None,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"blob_id": None,
|
|
|
|
"lfs": None,
|
|
|
|
"rfilename": "themes/theme_schema@0.2.5.json",
|
|
|
|
"size": None,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"blob_id": None,
|
|
|
|
"lfs": None,
|
|
|
|
"rfilename": "themes/theme_schema@1.5.9.json",
|
|
|
|
"size": None,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
tags=["gradio-theme", "gradio"],
|
2023-12-08 07:07:23 +08:00
|
|
|
private=False,
|
|
|
|
likes=0,
|
2023-03-19 11:15:02 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
assert get_theme_assets(space_info) == [
|
|
|
|
ThemeAsset("themes/theme_schema@0.1.0.json"),
|
|
|
|
ThemeAsset("themes/theme_schema@0.1.1.json"),
|
|
|
|
ThemeAsset("themes/theme_schema@0.2.5.json"),
|
|
|
|
ThemeAsset("themes/theme_schema@1.5.9.json"),
|
|
|
|
]
|
|
|
|
|
|
|
|
assert gr.Theme._theme_version_exists(space_info, "0.1.1")
|
|
|
|
assert not gr.Theme._theme_version_exists(space_info, "2.0.0")
|
|
|
|
|
2023-11-07 07:40:08 +08:00
|
|
|
@pytest.mark.flaky
|
|
|
|
def test_load_space_from_hub_works(self):
|
|
|
|
theme = gr.Theme.from_hub("gradio/seafoam")
|
|
|
|
assert isinstance(theme, gr.Theme)
|
|
|
|
|
2023-03-19 11:15:02 +08:00
|
|
|
|
2023-03-24 05:27:16 +08:00
|
|
|
class TestBuiltInThemes:
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"theme, name",
|
|
|
|
[
|
|
|
|
(gr.themes.Base(), "base"),
|
|
|
|
(gr.themes.Glass(), "glass"),
|
|
|
|
(gr.themes.Monochrome(), "monochrome"),
|
|
|
|
(gr.themes.Soft(), "soft"),
|
|
|
|
(gr.themes.Default(), "default"),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_theme_name(self, theme, name):
|
|
|
|
assert theme.name == name
|
|
|
|
|
|
|
|
|
2023-03-19 11:15:02 +08:00
|
|
|
class TestThemeUploadDownload:
|
|
|
|
@patch("gradio.themes.base.get_theme_assets", return_value=assets)
|
|
|
|
def test_get_next_version(self, mock):
|
|
|
|
next_version = gr.themes.Base._get_next_version(
|
2023-12-08 07:07:23 +08:00
|
|
|
SpaceInfo(id="gradio/dracula_test", private=False, likes=0, tags=[])
|
2023-03-19 11:15:02 +08:00
|
|
|
)
|
|
|
|
assert next_version == "3.20.2"
|
|
|
|
|
2023-10-31 21:48:10 +08:00
|
|
|
## Commenting out until after 4.0 Spaces are up
|
|
|
|
# @pytest.mark.flaky
|
|
|
|
# def test_theme_download(self):
|
|
|
|
# assert (
|
|
|
|
# gr.themes.Base.from_hub("gradio/dracula_test@0.0.2").to_dict()
|
|
|
|
# == dracula.to_dict()
|
|
|
|
# )
|
|
|
|
|
|
|
|
# with gr.Blocks(theme="gradio/dracula_test@0.0.2") as demo:
|
|
|
|
# pass
|
|
|
|
|
|
|
|
# assert demo.theme.to_dict() == dracula.to_dict()
|
|
|
|
# assert demo.theme.name == "gradio/dracula_test"
|
2023-03-19 11:15:02 +08:00
|
|
|
|
|
|
|
def test_theme_download_raises_error_if_theme_does_not_exist(self):
|
|
|
|
with pytest.raises(
|
|
|
|
ValueError, match="The space freddyaboulton/nonexistent does not exist"
|
|
|
|
):
|
|
|
|
gr.themes.Base.from_hub("freddyaboulton/nonexistent").to_dict()
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
@patch("gradio.themes.base.Base._theme_version_exists", return_value=True)
|
|
|
|
def test_theme_upload_fails_if_duplicate_version(self, mock_1, mock_2):
|
|
|
|
with pytest.raises(ValueError, match="already has a theme with version 0.2.1"):
|
|
|
|
dracula.push_to_hub("dracula_revamped", version="0.2.1", hf_token="foo")
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
@patch("gradio.themes.base.huggingface_hub.HfApi")
|
|
|
|
def test_upload_fails_if_not_valid_semver(self, mock_1, mock_2):
|
|
|
|
with pytest.raises(ValueError, match="Invalid version string: '3.0'"):
|
|
|
|
dracula.push_to_hub("dracula_revamped", version="3.0", hf_token="s")
|
|
|
|
|
|
|
|
def test_dump_and_load(self):
|
|
|
|
with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as path:
|
|
|
|
dracula.dump(path.name)
|
|
|
|
assert gr.themes.Base.load(path.name).to_dict() == dracula.to_dict()
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.Base._get_next_version", return_value="0.1.3")
|
|
|
|
@patch("gradio.themes.base.Base._theme_version_exists", return_value=False)
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
def test_version_and_token_optional(self, mock_1, mock_2, mock_3):
|
|
|
|
mock_1.whoami.return_value = {"name": "freddyaboulton"}
|
|
|
|
|
|
|
|
gr.themes.Monochrome().push_to_hub(repo_name="my_monochrome")
|
|
|
|
repo_call_args = mock_1.HfApi().create_commit.call_args_list[0][1]
|
|
|
|
assert repo_call_args["repo_id"] == "freddyaboulton/my_monochrome"
|
|
|
|
assert any(
|
|
|
|
o.path_in_repo == "themes/theme_schema@0.1.3.json"
|
|
|
|
for o in repo_call_args["operations"]
|
|
|
|
)
|
|
|
|
mock_1.whoami.assert_called_with()
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
def test_first_upload_no_version(self, mock_1):
|
|
|
|
mock_1.whoami.return_value = {"name": "freddyaboulton"}
|
|
|
|
|
|
|
|
mock_1.HfApi().space_info.side_effect = huggingface_hub.hf_api.HTTPError("Foo")
|
|
|
|
|
|
|
|
gr.themes.Monochrome().push_to_hub(repo_name="does_not_exist")
|
|
|
|
repo_call_args = mock_1.HfApi().create_commit.call_args_list[0][1]
|
|
|
|
assert repo_call_args["repo_id"] == "freddyaboulton/does_not_exist"
|
|
|
|
assert any(
|
|
|
|
o.path_in_repo == "themes/theme_schema@0.0.1.json"
|
|
|
|
for o in repo_call_args["operations"]
|
|
|
|
)
|
|
|
|
mock_1.whoami.assert_called_with()
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.Base._get_next_version", return_value="0.1.3")
|
|
|
|
@patch("gradio.themes.base.Base._theme_version_exists", return_value=False)
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
def test_can_pass_version_and_theme(self, mock_1, mock_2, mock_3):
|
|
|
|
mock_1.whoami.return_value = {"name": "freddyaboulton"}
|
|
|
|
|
|
|
|
gr.themes.Monochrome().push_to_hub(
|
|
|
|
repo_name="my_monochrome", version="0.1.5", hf_token="foo"
|
|
|
|
)
|
|
|
|
repo_call_args = mock_1.HfApi().create_commit.call_args_list[0][1]
|
|
|
|
assert repo_call_args["repo_id"] == "freddyaboulton/my_monochrome"
|
|
|
|
assert any(
|
|
|
|
o.path_in_repo == "themes/theme_schema@0.1.5.json"
|
|
|
|
for o in repo_call_args["operations"]
|
|
|
|
)
|
|
|
|
mock_1.whoami.assert_called_with(token="foo")
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
def test_raise_error_if_no_token_and_not_logged_in(self, mock_1):
|
|
|
|
mock_1.whoami.side_effect = OSError("not logged in")
|
|
|
|
|
|
|
|
with pytest.raises(
|
|
|
|
ValueError,
|
|
|
|
match="In order to push to hub, log in via `huggingface-cli login`",
|
|
|
|
):
|
|
|
|
gr.themes.Monochrome().push_to_hub(
|
|
|
|
repo_name="my_monochrome", version="0.1.5"
|
|
|
|
)
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.Base._get_next_version", return_value="0.1.3")
|
|
|
|
@patch("gradio.themes.base.Base._theme_version_exists", return_value=False)
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
def test_can_upload_to_org(self, mock_1, mock_2, mock_3):
|
|
|
|
mock_1.whoami.return_value = {"name": "freddyaboulton"}
|
|
|
|
|
|
|
|
gr.themes.Monochrome().push_to_hub(
|
|
|
|
repo_name="my_monochrome", version="0.1.9", org_name="gradio"
|
|
|
|
)
|
|
|
|
repo_call_args = mock_1.HfApi().create_commit.call_args_list[0][1]
|
|
|
|
assert repo_call_args["repo_id"] == "gradio/my_monochrome"
|
|
|
|
assert any(
|
|
|
|
o.path_in_repo == "themes/theme_schema@0.1.9.json"
|
|
|
|
for o in repo_call_args["operations"]
|
|
|
|
)
|
|
|
|
mock_1.whoami.assert_called_with()
|
|
|
|
|
|
|
|
@patch("gradio.themes.base.Base._get_next_version", return_value="0.1.3")
|
|
|
|
@patch("gradio.themes.base.Base._theme_version_exists", return_value=False)
|
|
|
|
@patch("gradio.themes.base.huggingface_hub")
|
|
|
|
def test_can_make_private(self, mock_1, mock_2, mock_3):
|
|
|
|
mock_1.whoami.return_value = {"name": "freddyaboulton"}
|
|
|
|
|
|
|
|
gr.themes.Monochrome().push_to_hub(
|
|
|
|
repo_name="my_monochrome", version="0.1.9", org_name="gradio", private=True
|
|
|
|
)
|
|
|
|
mock_1.create_repo.assert_called_with(
|
|
|
|
"gradio/my_monochrome",
|
|
|
|
repo_type="space",
|
|
|
|
space_sdk="gradio",
|
|
|
|
token=None,
|
|
|
|
exist_ok=True,
|
|
|
|
private=True,
|
|
|
|
)
|
2023-04-16 18:22:45 +08:00
|
|
|
|
|
|
|
|
|
|
|
def test_theme_builder_launches():
|
|
|
|
gr.themes.builder(prevent_thread_lock=True)
|
|
|
|
gr.close_all()
|