From 24c09d0319bd6046c9363a98880b8d2898ff2600 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Oct 2024 13:06:19 +0200 Subject: [PATCH] refactor: move ui deployment to it's own file --- freqtrade/commands/deploy_commands.py | 84 +++------------------------ freqtrade/commands/deploy_ui.py | 84 +++++++++++++++++++++++++++ tests/commands/test_commands.py | 34 +++++------ 3 files changed, 107 insertions(+), 95 deletions(-) create mode 100644 freqtrade/commands/deploy_ui.py diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index d610156ba..e389fc806 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -1,9 +1,7 @@ import logging import sys from pathlib import Path -from typing import Any, Dict, Optional, Tuple - -import requests +from typing import Any, Dict from freqtrade.constants import USERPATH_STRATEGIES from freqtrade.enums import RunMode @@ -101,80 +99,14 @@ def start_new_strategy(args: Dict[str, Any]) -> None: raise ConfigurationError("`new-strategy` requires --strategy to be set.") -def clean_ui_subdir(directory: Path): - if directory.is_dir(): - logger.info("Removing UI directory content.") - - for p in reversed(list(directory.glob("**/*"))): # iterate contents from leaves to root - if p.name in (".gitkeep", "fallback_file.html"): - continue - if p.is_file(): - p.unlink() - elif p.is_dir(): - p.rmdir() - - -def read_ui_version(dest_folder: Path) -> Optional[str]: - file = dest_folder / ".uiversion" - if not file.is_file(): - return None - - with file.open("r") as f: - return f.read() - - -def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): - from io import BytesIO - from zipfile import ZipFile - - logger.info(f"Downloading {dl_url}") - resp = requests.get(dl_url, timeout=req_timeout).content - dest_folder.mkdir(parents=True, exist_ok=True) - with ZipFile(BytesIO(resp)) as zf: - for fn in zf.filelist: - with zf.open(fn) as x: - destfile = dest_folder / fn.filename - if fn.is_dir(): - destfile.mkdir(exist_ok=True) - else: - destfile.write_bytes(x.read()) - with (dest_folder / ".uiversion").open("w") as f: - f.write(version) - - -def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]: - base_url = "https://api.github.com/repos/freqtrade/frequi/" - # Get base UI Repo path - - resp = requests.get(f"{base_url}releases", timeout=req_timeout) - resp.raise_for_status() - r = resp.json() - - if version: - tmp = [x for x in r if x["name"] == version] - if tmp: - latest_version = tmp[0]["name"] - assets = tmp[0].get("assets", []) - else: - raise ValueError("UI-Version not found.") - else: - latest_version = r[0]["name"] - assets = r[0].get("assets", []) - dl_url = "" - if assets and len(assets) > 0: - dl_url = assets[0]["browser_download_url"] - - # URL not found - try assets url - if not dl_url: - assets = r[0]["assets_url"] - resp = requests.get(assets, timeout=req_timeout) - r = resp.json() - dl_url = r[0]["browser_download_url"] - - return dl_url, latest_version - - def start_install_ui(args: Dict[str, Any]) -> None: + from freqtrade.commands.deploy_ui import ( + clean_ui_subdir, + download_and_install_ui, + get_ui_download_url, + read_ui_version, + ) + dest_folder = Path(__file__).parents[1] / "rpc/api_server/ui/installed/" # First make sure the assets are removed. dl_url, latest_version = get_ui_download_url(args.get("ui_version")) diff --git a/freqtrade/commands/deploy_ui.py b/freqtrade/commands/deploy_ui.py new file mode 100644 index 000000000..e9a9d2c43 --- /dev/null +++ b/freqtrade/commands/deploy_ui.py @@ -0,0 +1,84 @@ +import logging +from pathlib import Path +from typing import Optional, Tuple + +import requests + + +logger = logging.getLogger(__name__) + +# Timeout for requests +req_timeout = 30 + + +def clean_ui_subdir(directory: Path): + if directory.is_dir(): + logger.info("Removing UI directory content.") + + for p in reversed(list(directory.glob("**/*"))): # iterate contents from leaves to root + if p.name in (".gitkeep", "fallback_file.html"): + continue + if p.is_file(): + p.unlink() + elif p.is_dir(): + p.rmdir() + + +def read_ui_version(dest_folder: Path) -> Optional[str]: + file = dest_folder / ".uiversion" + if not file.is_file(): + return None + + with file.open("r") as f: + return f.read() + + +def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): + from io import BytesIO + from zipfile import ZipFile + + logger.info(f"Downloading {dl_url}") + resp = requests.get(dl_url, timeout=req_timeout).content + dest_folder.mkdir(parents=True, exist_ok=True) + with ZipFile(BytesIO(resp)) as zf: + for fn in zf.filelist: + with zf.open(fn) as x: + destfile = dest_folder / fn.filename + if fn.is_dir(): + destfile.mkdir(exist_ok=True) + else: + destfile.write_bytes(x.read()) + with (dest_folder / ".uiversion").open("w") as f: + f.write(version) + + +def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]: + base_url = "https://api.github.com/repos/freqtrade/frequi/" + # Get base UI Repo path + + resp = requests.get(f"{base_url}releases", timeout=req_timeout) + resp.raise_for_status() + r = resp.json() + + if version: + tmp = [x for x in r if x["name"] == version] + if tmp: + latest_version = tmp[0]["name"] + assets = tmp[0].get("assets", []) + else: + raise ValueError("UI-Version not found.") + else: + latest_version = r[0]["name"] + assets = r[0].get("assets", []) + dl_url = "" + if assets and len(assets) > 0: + dl_url = assets[0]["browser_download_url"] + + # URL not found - try assets url + if not dl_url: + assets = r[0]["assets_url"] + resp = requests.get(assets, timeout=req_timeout) + r = resp.json() + dl_url = r[0]["browser_download_url"] + + return dl_url, latest_version diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index ebc83e5e9..9ed3a2dd2 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -31,7 +31,7 @@ from freqtrade.commands import ( start_webserver, ) from freqtrade.commands.db_commands import start_convert_db -from freqtrade.commands.deploy_commands import ( +from freqtrade.commands.deploy_ui import ( clean_ui_subdir, download_and_install_ui, get_ui_download_url, @@ -612,13 +612,13 @@ def test_start_new_strategy_no_arg(mocker, caplog): def test_start_install_ui(mocker): - clean_mock = mocker.patch("freqtrade.commands.deploy_commands.clean_ui_subdir") + clean_mock = mocker.patch("freqtrade.commands.deploy_ui.clean_ui_subdir") get_url_mock = mocker.patch( - "freqtrade.commands.deploy_commands.get_ui_download_url", + "freqtrade.commands.deploy_ui.get_ui_download_url", return_value=("https://example.com/whatever", "0.0.1"), ) - download_mock = mocker.patch("freqtrade.commands.deploy_commands.download_and_install_ui") - mocker.patch("freqtrade.commands.deploy_commands.read_ui_version", return_value=None) + download_mock = mocker.patch("freqtrade.commands.deploy_ui.download_and_install_ui") + mocker.patch("freqtrade.commands.deploy_ui.read_ui_version", return_value=None) args = [ "install-ui", ] @@ -642,13 +642,13 @@ def test_start_install_ui(mocker): def test_clean_ui_subdir(mocker, tmp_path, caplog): - mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", side_effect=[True, True]) - mocker.patch("freqtrade.commands.deploy_commands.Path.is_file", side_effect=[False, True]) - rd_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.rmdir") - ul_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.unlink") + mocker.patch("freqtrade.commands.deploy_ui.Path.is_dir", side_effect=[True, True]) + mocker.patch("freqtrade.commands.deploy_ui.Path.is_file", side_effect=[False, True]) + rd_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.rmdir") + ul_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.unlink") mocker.patch( - "freqtrade.commands.deploy_commands.Path.glob", + "freqtrade.commands.deploy_ui.Path.glob", return_value=[Path("test1"), Path("test2"), Path(".gitkeep")], ) folder = tmp_path / "uitests" @@ -668,10 +668,10 @@ def test_download_and_install_ui(mocker, tmp_path): file_like_object.seek(0) requests_mock.content = file_like_object.read() - mocker.patch("requests.get", return_value=requests_mock) + mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=requests_mock) - mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", side_effect=[True, False]) - wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes") + mocker.patch("freqtrade.commands.deploy_ui.Path.is_dir", side_effect=[True, False]) + wb_mock = mocker.patch("freqtrade.commands.deploy_ui.Path.write_bytes") folder = tmp_path / "uitests_dl" folder.mkdir(exist_ok=True) @@ -693,9 +693,7 @@ def test_get_ui_download_url(mocker): [{"browser_download_url": "http://download.zip"}], ] ) - get_mock = mocker.patch( - "freqtrade.commands.deploy_commands.requests.get", return_value=response - ) + get_mock = mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=response) x, last_version = get_ui_download_url() assert get_mock.call_count == 2 assert last_version == "0.0.1" @@ -718,9 +716,7 @@ def test_get_ui_download_url_direct(mocker): }, ] ) - get_mock = mocker.patch( - "freqtrade.commands.deploy_commands.requests.get", return_value=response - ) + get_mock = mocker.patch("freqtrade.commands.deploy_ui.requests.get", return_value=response) x, last_version = get_ui_download_url() assert get_mock.call_count == 1 assert last_version == "0.0.2"