Merge pull request #10746 from xzmeng/startup-time

Postpone imports on demand
This commit is contained in:
Matthias
2024-10-06 08:21:54 +02:00
committed by GitHub
25 changed files with 498 additions and 406 deletions

View File

@@ -4,10 +4,10 @@ from unittest.mock import MagicMock
import pytest
import rapidjson
from freqtrade.commands.build_config_commands import (
from freqtrade.commands.build_config_commands import start_new_config
from freqtrade.configuration.deploy_config import (
ask_user_config,
ask_user_overwrite,
start_new_config,
validate_is_float,
validate_is_int,
)
@@ -39,7 +39,7 @@ def test_start_new_config(mocker, caplog, exchange):
wt_mock = mocker.patch.object(Path, "write_text", MagicMock())
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
unlink_mock = mocker.patch.object(Path, "unlink", MagicMock())
mocker.patch("freqtrade.commands.build_config_commands.ask_user_overwrite", return_value=True)
mocker.patch("freqtrade.configuration.deploy_config.ask_user_overwrite", return_value=True)
sample_selections = {
"max_open_trades": 3,
@@ -62,7 +62,7 @@ def test_start_new_config(mocker, caplog, exchange):
"api_server_password": "MoneyMachine",
}
mocker.patch(
"freqtrade.commands.build_config_commands.ask_user_config", return_value=sample_selections
"freqtrade.configuration.deploy_config.ask_user_config", return_value=sample_selections
)
args = ["new-config", "--config", "coolconfig.json"]
start_new_config(get_args(args))
@@ -80,7 +80,7 @@ def test_start_new_config(mocker, caplog, exchange):
def test_start_new_config_exists(mocker, caplog):
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
mocker.patch("freqtrade.commands.build_config_commands.ask_user_overwrite", return_value=False)
mocker.patch("freqtrade.configuration.deploy_config.ask_user_overwrite", return_value=False)
args = ["new-config", "--config", "coolconfig.json"]
with pytest.raises(OperationalException, match=r"Configuration .* already exists\."):
start_new_config(get_args(args))
@@ -91,14 +91,14 @@ def test_ask_user_overwrite(mocker):
Once https://github.com/tmbo/questionary/issues/35 is implemented, improve this test.
"""
prompt_mock = mocker.patch(
"freqtrade.commands.build_config_commands.prompt", return_value={"overwrite": False}
"freqtrade.configuration.deploy_config.prompt", return_value={"overwrite": False}
)
assert not ask_user_overwrite(Path("test.json"))
assert prompt_mock.call_count == 1
prompt_mock.reset_mock()
prompt_mock = mocker.patch(
"freqtrade.commands.build_config_commands.prompt", return_value={"overwrite": True}
"freqtrade.configuration.deploy_config.prompt", return_value={"overwrite": True}
)
assert ask_user_overwrite(Path("test.json"))
assert prompt_mock.call_count == 1
@@ -109,13 +109,13 @@ def test_ask_user_config(mocker):
Once https://github.com/tmbo/questionary/issues/35 is implemented, improve this test.
"""
prompt_mock = mocker.patch(
"freqtrade.commands.build_config_commands.prompt", return_value={"overwrite": False}
"freqtrade.configuration.deploy_config.prompt", return_value={"overwrite": False}
)
answers = ask_user_config()
assert isinstance(answers, dict)
assert prompt_mock.call_count == 1
prompt_mock = mocker.patch("freqtrade.commands.build_config_commands.prompt", return_value={})
prompt_mock = mocker.patch("freqtrade.configuration.deploy_config.prompt", return_value={})
with pytest.raises(OperationalException, match=r"User interrupted interactive questions\."):
ask_user_config()

View File

@@ -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,
@@ -571,8 +571,12 @@ def test_create_datadir_failed(caplog):
def test_create_datadir(caplog, mocker):
cud = mocker.patch("freqtrade.commands.deploy_commands.create_userdata_dir", MagicMock())
csf = mocker.patch("freqtrade.commands.deploy_commands.copy_sample_files", MagicMock())
cud = mocker.patch(
"freqtrade.configuration.directory_operations.create_userdata_dir", MagicMock()
)
csf = mocker.patch(
"freqtrade.configuration.directory_operations.copy_sample_files", MagicMock()
)
args = ["create-userdir", "--userdir", "/temp/freqtrade/test"]
start_create_userdir(get_args(args))
@@ -591,7 +595,7 @@ def test_start_new_strategy(mocker, caplog):
assert "CoolNewStrategy" in wt_mock.call_args_list[0][0][0]
assert log_has_re("Writing strategy to .*", caplog)
mocker.patch("freqtrade.commands.deploy_commands.setup_utils_configuration")
mocker.patch("freqtrade.configuration.setup_utils_configuration")
mocker.patch.object(Path, "exists", MagicMock(return_value=True))
with pytest.raises(
OperationalException, match=r".* already exists. Please choose another Strategy Name\."
@@ -608,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",
]
@@ -638,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"
@@ -664,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("freqtrade.commands.deploy_commands.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)
@@ -689,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"
@@ -714,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"
@@ -734,7 +734,7 @@ def test_get_ui_download_url_direct(mocker):
def test_download_data_keyboardInterrupt(mocker, markets):
dl_mock = mocker.patch(
"freqtrade.commands.data_commands.download_data_main",
"freqtrade.data.history.download_data_main",
MagicMock(side_effect=KeyboardInterrupt),
)
patch_exchange(mocker)
@@ -972,7 +972,7 @@ def test_download_data_data_invalid(mocker):
def test_start_convert_trades(mocker):
convert_mock = mocker.patch(
"freqtrade.commands.data_commands.convert_trades_to_ohlcv", MagicMock(return_value=[])
"freqtrade.data.converter.convert_trades_to_ohlcv", MagicMock(return_value=[])
)
patch_exchange(mocker)
mocker.patch(f"{EXMS}.get_markets")
@@ -1522,7 +1522,7 @@ def test_hyperopt_show(mocker, capsys):
mocker.patch(
"freqtrade.optimize.hyperopt_tools.HyperoptTools._read_results", side_effect=fake_iterator
)
mocker.patch("freqtrade.commands.hyperopt_commands.show_backtest_result")
mocker.patch("freqtrade.optimize.optimize_reports.show_backtest_result")
args = [
"hyperopt-show",
@@ -1579,8 +1579,8 @@ def test_hyperopt_show(mocker, capsys):
def test_convert_data(mocker, testdatadir):
ohlcv_mock = mocker.patch("freqtrade.commands.data_commands.convert_ohlcv_format")
trades_mock = mocker.patch("freqtrade.commands.data_commands.convert_trades_format")
ohlcv_mock = mocker.patch("freqtrade.data.converter.convert_ohlcv_format")
trades_mock = mocker.patch("freqtrade.data.converter.convert_trades_format")
args = [
"convert-data",
"--format-from",
@@ -1601,8 +1601,8 @@ def test_convert_data(mocker, testdatadir):
def test_convert_data_trades(mocker, testdatadir):
ohlcv_mock = mocker.patch("freqtrade.commands.data_commands.convert_ohlcv_format")
trades_mock = mocker.patch("freqtrade.commands.data_commands.convert_trades_format")
ohlcv_mock = mocker.patch("freqtrade.data.converter.convert_ohlcv_format")
trades_mock = mocker.patch("freqtrade.data.converter.convert_trades_format")
args = [
"convert-trade-data",
"--format-from",

View File

@@ -0,0 +1,17 @@
import subprocess
import time
MAXIMUM_STARTUP_TIME = 0.5
def test_startup_time():
# warm up to generate pyc
subprocess.run(["freqtrade", "-h"])
start = time.time()
subprocess.run(["freqtrade", "-h"])
elapsed = time.time() - start
assert (
elapsed < MAXIMUM_STARTUP_TIME
), "The startup time is too long, try to use lazy import in the command entry function"

View File

@@ -185,7 +185,7 @@ def test_api_ui_fallback(botclient, mocker):
def test_api_ui_version(botclient, mocker):
_ftbot, client = botclient
mocker.patch("freqtrade.commands.deploy_commands.read_ui_version", return_value="0.1.2")
mocker.patch("freqtrade.commands.deploy_ui.read_ui_version", return_value="0.1.2")
rc = client_get(client, "/ui_version")
assert rc.status_code == 200
assert rc.json()["version"] == "0.1.2"

View File

@@ -121,7 +121,7 @@ def test_main_operational_exception(mocker, default_conf, caplog) -> None:
def test_main_operational_exception1(mocker, default_conf, caplog) -> None:
patch_exchange(mocker)
mocker.patch(
"freqtrade.commands.list_commands.list_available_exchanges",
"freqtrade.exchange.list_available_exchanges",
MagicMock(side_effect=ValueError("Oh snap!")),
)
patched_configuration_load_config_file(mocker, default_conf)
@@ -135,7 +135,7 @@ def test_main_operational_exception1(mocker, default_conf, caplog) -> None:
assert log_has("Fatal exception!", caplog)
assert not log_has_re(r"SIGINT.*", caplog)
mocker.patch(
"freqtrade.commands.list_commands.list_available_exchanges",
"freqtrade.exchange.list_available_exchanges",
MagicMock(side_effect=KeyboardInterrupt),
)
with pytest.raises(SystemExit):
@@ -147,7 +147,7 @@ def test_main_operational_exception1(mocker, default_conf, caplog) -> None:
def test_main_ConfigurationError(mocker, default_conf, caplog) -> None:
patch_exchange(mocker)
mocker.patch(
"freqtrade.commands.list_commands.list_available_exchanges",
"freqtrade.exchange.list_available_exchanges",
MagicMock(side_effect=ConfigurationError("Oh snap!")),
)
patched_configuration_load_config_file(mocker, default_conf)