diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 432bf429924..d0bad456797 100755 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -347,7 +347,7 @@ def _build_subcommands(self) -> None: self.parser = ArgumentParser( prog="freqtrade", description="Free, open source crypto trading bot" ) - self._build_args(optionlist=["version"], parser=self.parser) + self._build_args(optionlist=["version_main"], parser=self.parser) from freqtrade.commands import ( start_analysis_entries_exits, diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 54cd56e52aa..16f5d1c4d97 100755 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -4,7 +4,7 @@ from argparse import SUPPRESS, ArgumentTypeError -from freqtrade import __version__, constants +from freqtrade import constants from freqtrade.constants import HYPEROPT_LOSS_BUILTIN from freqtrade.enums import CandleType @@ -59,8 +59,15 @@ def __init__(self, *args, **kwargs): "version": Arg( "-V", "--version", - action="version", - version=f"%(prog)s {__version__}", + help="show program's version number and exit", + action="store_true", + ), + "version_main": Arg( + # Copy of version - used to have -V available with and without subcommand. + "-V", + "--version", + help="show program's version number and exit", + action="store_true", ), "config": Arg( "-c", diff --git a/freqtrade/main.py b/freqtrade/main.py index bd815b74652..d4aab346825 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -18,7 +18,7 @@ from freqtrade.constants import DOCS_LINK from freqtrade.exceptions import ConfigurationError, FreqtradeException, OperationalException from freqtrade.loggers import setup_logging_pre -from freqtrade.system import asyncio_setup, gc_set_threshold +from freqtrade.system import asyncio_setup, gc_set_threshold, print_version_info logger = logging.getLogger("freqtrade") @@ -38,7 +38,10 @@ def main(sysargv: list[str] | None = None) -> None: args = arguments.get_parsed_arg() # Call subcommand. - if "func" in args: + if args.get("version") or args.get("version_main"): + print_version_info() + return_code = 0 + elif "func" in args: logger.info(f"freqtrade {__version__}") gc_set_threshold() return_code = args["func"](args) diff --git a/freqtrade/system/__init__.py b/freqtrade/system/__init__.py index 10a23aa4b86..e69e90de8eb 100644 --- a/freqtrade/system/__init__.py +++ b/freqtrade/system/__init__.py @@ -2,6 +2,7 @@ from freqtrade.system.asyncio_config import asyncio_setup from freqtrade.system.gc_setup import gc_set_threshold +from freqtrade.system.version_info import print_version_info -__all__ = ["asyncio_setup", "gc_set_threshold"] +__all__ = ["asyncio_setup", "gc_set_threshold", "print_version_info"] diff --git a/freqtrade/system/version_info.py b/freqtrade/system/version_info.py new file mode 100644 index 00000000000..505992a7fd3 --- /dev/null +++ b/freqtrade/system/version_info.py @@ -0,0 +1,15 @@ +from freqtrade import __version__ + + +def print_version_info(): + """Print version information for freqtrade and its key dependencies.""" + import platform + import sys + + import ccxt + + print(f"Operating System:\t{platform.platform()}") + print(f"Python Version:\t\tPython {sys.version.split(' ')[0]}") + print(f"CCXT Version:\t\t{ccxt.__version__}") + print() + print(f"Freqtrade Version:\tfreqtrade {__version__}") diff --git a/tests/test_arguments.py b/tests/test_arguments.py index 499b194a2c3..1d48acb96d0 100644 --- a/tests/test_arguments.py +++ b/tests/test_arguments.py @@ -82,8 +82,8 @@ def test_common_scripts_options() -> None: def test_parse_args_version() -> None: - with pytest.raises(SystemExit, match=r"0"): - Arguments(["--version"]).get_parsed_arg() + args = Arguments(["--version"]).get_parsed_arg() + assert args["version_main"] is True def test_parse_args_invalid() -> None: diff --git a/tests/test_main.py b/tests/test_main.py index 54b00a7d838..0551def2d6b 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,5 +1,6 @@ # pragma pylint: disable=missing-docstring +import re from copy import deepcopy from pathlib import Path from unittest.mock import MagicMock, PropertyMock @@ -26,6 +27,14 @@ def test_parse_args_None(caplog) -> None: assert log_has_re(r"Usage of Freqtrade requires a subcommand.*", caplog) +def test_parse_args_version(capsys) -> None: + with pytest.raises(SystemExit): + main(["-V"]) + captured = capsys.readouterr() + assert re.search(r"CCXT Version:\s.*", captured.out, re.MULTILINE) + assert re.search(r"Freqtrade Version:\s+freqtrade\s.*", captured.out, re.MULTILINE) + + def test_parse_args_backtesting(mocker) -> None: """ Test that main() can start backtesting and also ensure we can pass some specific arguments