From 48a8d7de1c61e0825efbe0370df3c2d108b56872 Mon Sep 17 00:00:00 2001 From: Meng Xiangzhuo Date: Thu, 3 Oct 2024 11:33:52 +0800 Subject: [PATCH] Postpone imports on demand --- freqtrade/commands/analyze_commands.py | 3 +- freqtrade/commands/build_config_commands.py | 23 ++++++---- freqtrade/commands/data_commands.py | 29 +++++++----- freqtrade/commands/db_commands.py | 5 +-- freqtrade/commands/deploy_commands.py | 15 ++++--- freqtrade/commands/hyperopt_commands.py | 8 ++-- freqtrade/commands/list_commands.py | 44 ++++++++++++++----- freqtrade/commands/optimize_commands.py | 8 +++- freqtrade/commands/pairlist_commands.py | 4 +- freqtrade/commands/plot_commands.py | 3 +- freqtrade/commands/strategy_utils_commands.py | 7 +-- freqtrade/data/btanalysis.py | 10 ++++- freqtrade/main.py | 3 +- freqtrade/{util/gc_setup.py => system.py} | 12 +++++ freqtrade/util/migrations/funding_rate_mig.py | 3 +- pyproject.toml | 2 + tests/commands/test_build_config.py | 15 +++---- tests/commands/test_commands.py | 34 +++++++------- tests/data/test_btanalysis.py | 2 +- tests/test_main.py | 6 +-- 20 files changed, 151 insertions(+), 85 deletions(-) rename freqtrade/{util/gc_setup.py => system.py} (61%) diff --git a/freqtrade/commands/analyze_commands.py b/freqtrade/commands/analyze_commands.py index 7d605a228..0b07d335b 100644 --- a/freqtrade/commands/analyze_commands.py +++ b/freqtrade/commands/analyze_commands.py @@ -2,7 +2,6 @@ import logging from pathlib import Path from typing import Any, Dict -from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import ConfigurationError, OperationalException @@ -17,6 +16,8 @@ def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[s :param method: Bot running mode :return: Configuration """ + from freqtrade.configuration import setup_utils_configuration + config = setup_utils_configuration(args, method) no_unlimited_runmodes = { diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index cb64e4da9..3bcc5254f 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -3,17 +3,9 @@ import secrets from pathlib import Path from typing import Any, Dict, List -from questionary import Separator, prompt - -from freqtrade.configuration import sanitize_config -from freqtrade.configuration.config_setup import setup_utils_configuration -from freqtrade.configuration.detect_environment import running_in_docker -from freqtrade.configuration.directory_operations import chown_user_directory from freqtrade.constants import UNLIMITED_STAKE_AMOUNT from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException -from freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges -from freqtrade.util import render_template logger = logging.getLogger(__name__) @@ -36,6 +28,8 @@ def validate_is_float(val): def ask_user_overwrite(config_path: Path) -> bool: + from questionary import prompt + questions = [ { "type": "confirm", @@ -54,6 +48,11 @@ def ask_user_config() -> Dict[str, Any]: Interactive questions built using https://github.com/tmbo/questionary :returns: Dict with keys to put into template """ + from questionary import Separator, prompt + + from freqtrade.configuration.detect_environment import running_in_docker + from freqtrade.exchange import available_exchanges + questions: List[Dict[str, Any]] = [ { "type": "confirm", @@ -227,6 +226,9 @@ def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: """ from jinja2.exceptions import TemplateNotFound + from freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS + from freqtrade.util import render_template + try: exchange_template = MAP_EXCHANGE_CHILDCLASS.get( selections["exchange_name"], selections["exchange_name"] @@ -256,6 +258,8 @@ def start_new_config(args: Dict[str, Any]) -> None: Asking the user questions to fill out the template accordingly. """ + from freqtrade.configuration.directory_operations import chown_user_directory + config_path = Path(args["config"][0]) chown_user_directory(config_path.parent) if config_path.exists(): @@ -272,6 +276,9 @@ def start_new_config(args: Dict[str, Any]) -> None: def start_show_config(args: Dict[str, Any]) -> None: + from freqtrade.configuration import sanitize_config + from freqtrade.configuration.config_setup import setup_utils_configuration + config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE, set_dry=False) print("Your combined configuration is:") diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index a114444b3..9ce039b22 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -3,22 +3,10 @@ import sys from collections import defaultdict from typing import Any, Dict -from freqtrade.configuration import TimeRange, setup_utils_configuration from freqtrade.constants import DATETIME_PRINT_FORMAT, DL_DATA_TIMEFRAMES, Config -from freqtrade.data.converter import ( - convert_ohlcv_format, - convert_trades_format, - convert_trades_to_ohlcv, -) -from freqtrade.data.history import download_data_main from freqtrade.enums import CandleType, RunMode, TradingMode from freqtrade.exceptions import ConfigurationError -from freqtrade.exchange import timeframe_to_minutes -from freqtrade.misc import plural from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist -from freqtrade.resolvers import ExchangeResolver -from freqtrade.util import print_rich_table -from freqtrade.util.migrations import migrate_data logger = logging.getLogger(__name__) @@ -42,6 +30,9 @@ def start_download_data(args: Dict[str, Any]) -> None: """ Download data (former download_backtest_data.py script) """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.data.history import download_data_main + config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) _check_data_config_download_sanity(config) @@ -54,6 +45,10 @@ def start_download_data(args: Dict[str, Any]) -> None: def start_convert_trades(args: Dict[str, Any]) -> None: + from freqtrade.configuration import TimeRange, setup_utils_configuration + from freqtrade.data.converter import convert_trades_to_ohlcv + from freqtrade.resolvers import ExchangeResolver + config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) timerange = TimeRange() @@ -96,6 +91,10 @@ def start_convert_data(args: Dict[str, Any], ohlcv: bool = True) -> None: """ Convert data from one format to another """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.data.converter import convert_ohlcv_format, convert_trades_format + from freqtrade.util.migrations import migrate_data + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) if ohlcv: migrate_data(config) @@ -118,6 +117,9 @@ def start_list_data(args: Dict[str, Any]) -> None: """ List available OHLCV data """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.exchange import timeframe_to_minutes + from freqtrade.util import print_rich_table if args["trades"]: start_list_trades_data(args) @@ -181,6 +183,9 @@ def start_list_trades_data(args: Dict[str, Any]) -> None: """ List available Trades data """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.misc import plural + from freqtrade.util import print_rich_table config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) diff --git a/freqtrade/commands/db_commands.py b/freqtrade/commands/db_commands.py index 98af38ca4..1c346ad7a 100644 --- a/freqtrade/commands/db_commands.py +++ b/freqtrade/commands/db_commands.py @@ -1,9 +1,6 @@ import logging from typing import Any, Dict -from sqlalchemy import func, select - -from freqtrade.configuration.config_setup import setup_utils_configuration from freqtrade.enums import RunMode @@ -11,8 +8,10 @@ logger = logging.getLogger(__name__) def start_convert_db(args: Dict[str, Any]) -> None: + from sqlalchemy import func, select from sqlalchemy.orm import make_transient + from freqtrade.configuration.config_setup import setup_utils_configuration from freqtrade.persistence import Order, Trade, init_db from freqtrade.persistence.migrations import set_sequence_ids from freqtrade.persistence.pairlock import PairLock diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 3a784bda9..f96716d7b 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -3,14 +3,9 @@ import sys from pathlib import Path from typing import Any, Dict, Optional, Tuple -import requests - -from freqtrade.configuration import setup_utils_configuration -from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir from freqtrade.constants import USERPATH_STRATEGIES from freqtrade.enums import RunMode from freqtrade.exceptions import ConfigurationError, OperationalException -from freqtrade.util import render_template, render_template_with_fallback logger = logging.getLogger(__name__) @@ -26,6 +21,8 @@ def start_create_userdir(args: Dict[str, Any]) -> None: :param args: Cli args from Arguments() :return: None """ + from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir + if "user_data_dir" in args and args["user_data_dir"]: userdir = create_userdata_dir(args["user_data_dir"], create_dir=True) copy_sample_files(userdir, overwrite=args["reset"]) @@ -38,6 +35,8 @@ def deploy_new_strategy(strategy_name: str, strategy_path: Path, subtemplate: st """ Deploy new strategy from template to strategy_path """ + from freqtrade.util import render_template, render_template_with_fallback + fallback = "full" attributes = render_template_with_fallback( templatefile=f"strategy_subtemplates/strategy_attributes_{subtemplate}.j2", @@ -82,6 +81,8 @@ def deploy_new_strategy(strategy_name: str, strategy_path: Path, subtemplate: st def start_new_strategy(args: Dict[str, Any]) -> None: + from freqtrade.configuration import setup_utils_configuration + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) if "strategy" in args and args["strategy"]: @@ -124,6 +125,8 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): from io import BytesIO from zipfile import ZipFile + import requests + logger.info(f"Downloading {dl_url}") resp = requests.get(dl_url, timeout=req_timeout).content dest_folder.mkdir(parents=True, exist_ok=True) @@ -140,6 +143,8 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]: + import requests + base_url = "https://api.github.com/repos/freqtrade/frequi/" # Get base UI Repo path diff --git a/freqtrade/commands/hyperopt_commands.py b/freqtrade/commands/hyperopt_commands.py index d89d25796..ccf319e9e 100644 --- a/freqtrade/commands/hyperopt_commands.py +++ b/freqtrade/commands/hyperopt_commands.py @@ -2,11 +2,8 @@ import logging from operator import itemgetter from typing import Any, Dict -from freqtrade.configuration import setup_utils_configuration -from freqtrade.data.btanalysis import get_latest_hyperopt_file from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException -from freqtrade.optimize.optimize_reports import show_backtest_result logger = logging.getLogger(__name__) @@ -16,6 +13,8 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None: """ List hyperopt epochs previously evaluated """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.data.btanalysis import get_latest_hyperopt_file from freqtrade.optimize.hyperopt_output import HyperoptOutput from freqtrade.optimize.hyperopt_tools import HyperoptTools @@ -61,7 +60,10 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None: """ Show details of a hyperopt epoch previously evaluated """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.data.btanalysis import get_latest_hyperopt_file from freqtrade.optimize.hyperopt_tools import HyperoptTools + from freqtrade.optimize.optimize_reports import show_backtest_result config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index af6e4571f..c99830aa8 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -1,21 +1,19 @@ +from __future__ import annotations + import csv import logging import sys +import typing from typing import Any, Dict, List, Union import rapidjson -from rich.console import Console -from rich.table import Table -from rich.text import Text -from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import ConfigurationError, OperationalException -from freqtrade.exchange import list_available_exchanges, market_is_active -from freqtrade.ft_types import ValidExchangesType -from freqtrade.misc import parse_db_uri_for_logging, plural -from freqtrade.resolvers import ExchangeResolver, StrategyResolver -from freqtrade.util import print_rich_table + + +if typing.TYPE_CHECKING: + from freqtrade.ft_types import ValidExchangesType logger = logging.getLogger(__name__) @@ -27,6 +25,12 @@ def start_list_exchanges(args: Dict[str, Any]) -> None: :param args: Cli args from Arguments() :return: None """ + from rich.console import Console + from rich.table import Table + from rich.text import Text + + from freqtrade.exchange import list_available_exchanges + available_exchanges: List[ValidExchangesType] = list_available_exchanges( args["list_exchanges_all"] ) @@ -86,6 +90,10 @@ def start_list_exchanges(args: Dict[str, Any]) -> None: def _print_objs_tabular(objs: List, print_colorized: bool) -> None: + from rich.console import Console + from rich.table import Table + from rich.text import Text + names = [s["name"] for s in objs] objs_to_print: List[Dict[str, Union[Text, str]]] = [ { @@ -129,6 +137,9 @@ def start_list_strategies(args: Dict[str, Any]) -> None: """ Print files with Strategy custom classes available in the directory """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.resolvers import StrategyResolver + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) strategy_objs = StrategyResolver.search_all_objects( @@ -152,9 +163,11 @@ def start_list_freqAI_models(args: Dict[str, Any]) -> None: """ Print files with FreqAI models custom classes available in the directory """ - config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) + from freqtrade.configuration import setup_utils_configuration from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver + config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) + model_objs = FreqaiModelResolver.search_all_objects(config, not args["print_one_column"]) # Sort alphabetically model_objs = sorted(model_objs, key=lambda x: x["name"]) @@ -168,6 +181,9 @@ def start_list_timeframes(args: Dict[str, Any]) -> None: """ Print timeframes available on Exchange """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.resolvers import ExchangeResolver + config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) # Do not use timeframe set in the config config["timeframe"] = None @@ -191,6 +207,12 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None: :param pairs_only: if True print only pairs, otherwise print all instruments (markets) :return: None """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.exchange import market_is_active + from freqtrade.misc import plural + from freqtrade.resolvers import ExchangeResolver + from freqtrade.util import print_rich_table + config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) # Init exchange @@ -302,6 +324,8 @@ def start_show_trades(args: Dict[str, Any]) -> None: """ import json + from freqtrade.configuration import setup_utils_configuration + from freqtrade.misc import parse_db_uri_for_logging from freqtrade.persistence import Trade, init_db config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) diff --git a/freqtrade/commands/optimize_commands.py b/freqtrade/commands/optimize_commands.py index aa055469a..d8240f660 100644 --- a/freqtrade/commands/optimize_commands.py +++ b/freqtrade/commands/optimize_commands.py @@ -2,10 +2,8 @@ import logging from typing import Any, Dict from freqtrade import constants -from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import ConfigurationError, OperationalException -from freqtrade.util import fmt_coin logger = logging.getLogger(__name__) @@ -18,6 +16,9 @@ def setup_optimize_configuration(args: Dict[str, Any], method: RunMode) -> Dict[ :param method: Bot running mode :return: Configuration """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.util import fmt_coin + config = setup_utils_configuration(args, method) no_unlimited_runmodes = { @@ -64,6 +65,7 @@ def start_backtesting_show(args: Dict[str, Any]) -> None: """ Show previous backtest result """ + from freqtrade.configuration import setup_utils_configuration config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) @@ -144,6 +146,7 @@ def start_lookahead_analysis(args: Dict[str, Any]) -> None: :param args: Cli args from Arguments() :return: None """ + from freqtrade.configuration import setup_utils_configuration from freqtrade.optimize.analysis.lookahead_helpers import LookaheadAnalysisSubFunctions config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) @@ -156,6 +159,7 @@ def start_recursive_analysis(args: Dict[str, Any]) -> None: :param args: Cli args from Arguments() :return: None """ + from freqtrade.configuration import setup_utils_configuration from freqtrade.optimize.analysis.recursive_helpers import RecursiveAnalysisSubFunctions config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) diff --git a/freqtrade/commands/pairlist_commands.py b/freqtrade/commands/pairlist_commands.py index 8b2963563..b027a222d 100644 --- a/freqtrade/commands/pairlist_commands.py +++ b/freqtrade/commands/pairlist_commands.py @@ -3,9 +3,7 @@ from typing import Any, Dict import rapidjson -from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode -from freqtrade.resolvers import ExchangeResolver logger = logging.getLogger(__name__) @@ -15,8 +13,10 @@ def start_test_pairlist(args: Dict[str, Any]) -> None: """ Test Pairlist configuration """ + from freqtrade.configuration import setup_utils_configuration from freqtrade.persistence import FtNoDBContext from freqtrade.plugins.pairlistmanager import PairListManager + from freqtrade.resolvers import ExchangeResolver config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) diff --git a/freqtrade/commands/plot_commands.py b/freqtrade/commands/plot_commands.py index 4b939cc80..4ed698bf2 100644 --- a/freqtrade/commands/plot_commands.py +++ b/freqtrade/commands/plot_commands.py @@ -1,6 +1,5 @@ from typing import Any, Dict -from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode from freqtrade.exceptions import ConfigurationError @@ -18,6 +17,7 @@ def start_plot_dataframe(args: Dict[str, Any]) -> None: Entrypoint for dataframe plotting """ # Import here to avoid errors if plot-dependencies are not installed. + from freqtrade.configuration import setup_utils_configuration from freqtrade.plot.plotting import load_and_plot_trades validate_plot_args(args) @@ -31,6 +31,7 @@ def start_plot_profit(args: Dict[str, Any]) -> None: Entrypoint for plot_profit """ # Import here to avoid errors if plot-dependencies are not installed. + from freqtrade.configuration import setup_utils_configuration from freqtrade.plot.plotting import plot_profit validate_plot_args(args) diff --git a/freqtrade/commands/strategy_utils_commands.py b/freqtrade/commands/strategy_utils_commands.py index 761a7262c..785e89aee 100644 --- a/freqtrade/commands/strategy_utils_commands.py +++ b/freqtrade/commands/strategy_utils_commands.py @@ -4,10 +4,7 @@ import time from pathlib import Path from typing import Any, Dict -from freqtrade.configuration import setup_utils_configuration from freqtrade.enums import RunMode -from freqtrade.resolvers import StrategyResolver -from freqtrade.strategy.strategyupdater import StrategyUpdater logger = logging.getLogger(__name__) @@ -19,6 +16,8 @@ def start_strategy_update(args: Dict[str, Any]) -> None: :param args: Cli args from Arguments() :return: None """ + from freqtrade.configuration import setup_utils_configuration + from freqtrade.resolvers import StrategyResolver if sys.version_info == (3, 8): # pragma: no cover sys.exit("Freqtrade strategy updater requires Python version >= 3.9") @@ -49,6 +48,8 @@ def start_strategy_update(args: Dict[str, Any]) -> None: def start_conversion(strategy_obj, config): + from freqtrade.strategy.strategyupdater import StrategyUpdater + print(f"Conversion of {Path(strategy_obj['location']).name} started.") instance_strategy_updater = StrategyUpdater() start = time.perf_counter() diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 580807a76..ad90014c2 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -2,7 +2,10 @@ Helpers when analyzing backtest data """ +from __future__ import annotations + import logging +import typing from copy import copy from datetime import datetime, timezone from pathlib import Path @@ -16,7 +19,10 @@ from freqtrade.exceptions import ConfigurationError, OperationalException from freqtrade.ft_types import BacktestHistoryEntryType, BacktestResultType from freqtrade.misc import file_dump_json, json_load from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename -from freqtrade.persistence import LocalTrade, Trade, init_db + + +if typing.TYPE_CHECKING: + from freqtrade.persistence import LocalTrade, Trade logger = logging.getLogger(__name__) @@ -460,6 +466,8 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF Can also serve as protection to load the correct result. :return: Dataframe containing Trades """ + from freqtrade.persistence import Trade, init_db + init_db(db_url) filters = [] diff --git a/freqtrade/main.py b/freqtrade/main.py index 67584c5b7..dd034477a 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -15,11 +15,10 @@ if sys.version_info < (3, 9): # pragma: no cover from freqtrade import __version__ from freqtrade.commands import Arguments -from freqtrade.configuration import asyncio_setup from freqtrade.constants import DOCS_LINK from freqtrade.exceptions import ConfigurationError, FreqtradeException, OperationalException from freqtrade.loggers import setup_logging_pre -from freqtrade.util.gc_setup import gc_set_threshold +from freqtrade.system import asyncio_setup, gc_set_threshold logger = logging.getLogger("freqtrade") diff --git a/freqtrade/util/gc_setup.py b/freqtrade/system.py similarity index 61% rename from freqtrade/util/gc_setup.py rename to freqtrade/system.py index a3532cbab..c7be18ec0 100644 --- a/freqtrade/util/gc_setup.py +++ b/freqtrade/system.py @@ -1,11 +1,23 @@ +"""System specific or performance tuning""" + import gc import logging import platform +import sys logger = logging.getLogger(__name__) +def asyncio_setup() -> None: # pragma: no cover + # Set eventloop for win32 setups + + if sys.platform == "win32": + import asyncio + + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + def gc_set_threshold(): """ Reduce number of GC runs to improve performance (explanation video) diff --git a/freqtrade/util/migrations/funding_rate_mig.py b/freqtrade/util/migrations/funding_rate_mig.py index 16ca60732..e53ec339e 100644 --- a/freqtrade/util/migrations/funding_rate_mig.py +++ b/freqtrade/util/migrations/funding_rate_mig.py @@ -2,7 +2,6 @@ import logging from typing import Optional from freqtrade.constants import Config -from freqtrade.data.history import get_datahandler from freqtrade.enums import TradingMode from freqtrade.exchange import Exchange @@ -11,6 +10,8 @@ logger = logging.getLogger(__name__) def migrate_funding_fee_timeframe(config: Config, exchange: Optional[Exchange]): + from freqtrade.data.history import get_datahandler + if config.get("trading_mode", TradingMode.SPOT) != TradingMode.FUTURES: # only act on futures return diff --git a/pyproject.toml b/pyproject.toml index bd36d15c6..0229b8284 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -160,6 +160,8 @@ extend-ignore = [ "S607", # Starting a process with a partial executable path "S608", # Possible SQL injection vector through string-based query construction "NPY002", # Numpy legacy random generator + "UP006", # non-pep585-annotation + "UP007", # non-pep604-annotation ] [tool.ruff.lint.mccabe] diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py index 5d287a35f..6efda2ff8 100644 --- a/tests/commands/test_build_config.py +++ b/tests/commands/test_build_config.py @@ -90,16 +90,13 @@ 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} - ) + prompt_mock = mocker.patch("questionary.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} - ) + + prompt_mock = mocker.patch("questionary.prompt", return_value={"overwrite": True}) assert ask_user_overwrite(Path("test.json")) assert prompt_mock.call_count == 1 @@ -108,14 +105,12 @@ 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} - ) + prompt_mock = mocker.patch("questionary.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("questionary.prompt", return_value={}) with pytest.raises(OperationalException, match=r"User interrupted interactive questions\."): ask_user_config() diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index c55126db1..9be7f9506 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -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\." @@ -664,7 +668,7 @@ 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("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") @@ -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("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("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", diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index b9dee6d59..691b02fc0 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -146,7 +146,7 @@ def test_load_backtest_data_multi(testdatadir): def test_load_trades_from_db(default_conf, fee, is_short, mocker): create_mock_trades(fee, is_short) # remove init so it does not init again - init_mock = mocker.patch("freqtrade.data.btanalysis.init_db", MagicMock()) + init_mock = mocker.patch("freqtrade.persistence.init_db", MagicMock()) trades = load_trades_from_db(db_url=default_conf["db_url"]) assert init_mock.call_count == 1 diff --git a/tests/test_main.py b/tests/test_main.py index b230d4e99..3c8150c38 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -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)