Merge pull request #4308 from eatrisno/patch-1
Add Refresh / Reload Button on rpc/Telegram
This commit is contained in:
commit
204758834d
@ -178,7 +178,9 @@
|
|||||||
"sell_fill": "on",
|
"sell_fill": "on",
|
||||||
"buy_cancel": "on",
|
"buy_cancel": "on",
|
||||||
"sell_cancel": "on"
|
"sell_cancel": "on"
|
||||||
}
|
},
|
||||||
|
"reload": true,
|
||||||
|
"balance_dust_level": 0.01
|
||||||
},
|
},
|
||||||
"api_server": {
|
"api_server": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
@ -95,6 +95,7 @@ Example configuration showing the different settings:
|
|||||||
"buy_fill": "off",
|
"buy_fill": "off",
|
||||||
"sell_fill": "off"
|
"sell_fill": "off"
|
||||||
},
|
},
|
||||||
|
"reload": true,
|
||||||
"balance_dust_level": 0.01
|
"balance_dust_level": 0.01
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
@ -105,6 +106,7 @@ Example configuration showing the different settings:
|
|||||||
|
|
||||||
|
|
||||||
`balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown.
|
`balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown.
|
||||||
|
`reload` allows you to disable reload-buttons on selected messages.
|
||||||
|
|
||||||
## Create a custom keyboard (command shortcut buttons)
|
## Create a custom keyboard (command shortcut buttons)
|
||||||
|
|
||||||
|
@ -275,7 +275,8 @@ CONF_SCHEMA = {
|
|||||||
'default': 'off'
|
'default': 'off'
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
'reload': {'type': 'boolean'},
|
||||||
},
|
},
|
||||||
'required': ['enabled', 'token', 'chat_id'],
|
'required': ['enabled', 'token', 'chat_id'],
|
||||||
},
|
},
|
||||||
|
@ -10,13 +10,13 @@ from datetime import date, datetime, timedelta
|
|||||||
from html import escape
|
from html import escape
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from math import isnan
|
from math import isnan
|
||||||
from typing import Any, Callable, Dict, List, Optional, Union, cast
|
from typing import Any, Callable, Dict, List, Optional, Union
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from telegram import (InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ParseMode,
|
from telegram import (CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton,
|
||||||
ReplyKeyboardMarkup, Update)
|
ParseMode, ReplyKeyboardMarkup, Update)
|
||||||
from telegram.error import NetworkError, TelegramError
|
from telegram.error import BadRequest, NetworkError, TelegramError
|
||||||
from telegram.ext import CallbackContext, CallbackQueryHandler, CommandHandler, Updater
|
from telegram.ext import CallbackContext, CallbackQueryHandler, CommandHandler, Updater
|
||||||
from telegram.utils.helpers import escape_markdown
|
from telegram.utils.helpers import escape_markdown
|
||||||
|
|
||||||
@ -47,9 +47,13 @@ def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]:
|
|||||||
update = kwargs.get('update') or args[0]
|
update = kwargs.get('update') or args[0]
|
||||||
|
|
||||||
# Reject unauthorized messages
|
# Reject unauthorized messages
|
||||||
chat_id = int(self._config['telegram']['chat_id'])
|
if update.callback_query:
|
||||||
|
cchat_id = int(update.callback_query.message.chat.id)
|
||||||
|
else:
|
||||||
|
cchat_id = int(update.message.chat_id)
|
||||||
|
|
||||||
if int(update.message.chat_id) != chat_id:
|
chat_id = int(self._config['telegram']['chat_id'])
|
||||||
|
if cchat_id != chat_id:
|
||||||
logger.info(
|
logger.info(
|
||||||
'Rejected unauthorized message from: %s',
|
'Rejected unauthorized message from: %s',
|
||||||
update.message.chat_id
|
update.message.chat_id
|
||||||
@ -91,7 +95,7 @@ class Telegram(RPCHandler):
|
|||||||
Validates the keyboard configuration from telegram config
|
Validates the keyboard configuration from telegram config
|
||||||
section.
|
section.
|
||||||
"""
|
"""
|
||||||
self._keyboard: List[List[Union[str, KeyboardButton, InlineKeyboardButton]]] = [
|
self._keyboard: List[List[Union[str, KeyboardButton]]] = [
|
||||||
['/daily', '/profit', '/balance'],
|
['/daily', '/profit', '/balance'],
|
||||||
['/status', '/status table', '/performance'],
|
['/status', '/status table', '/performance'],
|
||||||
['/count', '/start', '/stop', '/help']
|
['/count', '/start', '/stop', '/help']
|
||||||
@ -164,8 +168,21 @@ class Telegram(RPCHandler):
|
|||||||
CommandHandler('help', self._help),
|
CommandHandler('help', self._help),
|
||||||
CommandHandler('version', self._version),
|
CommandHandler('version', self._version),
|
||||||
]
|
]
|
||||||
|
callbacks = [
|
||||||
|
CallbackQueryHandler(self._status_table, pattern='update_status_table'),
|
||||||
|
CallbackQueryHandler(self._daily, pattern='update_daily'),
|
||||||
|
CallbackQueryHandler(self._profit, pattern='update_profit'),
|
||||||
|
CallbackQueryHandler(self._balance, pattern='update_balance'),
|
||||||
|
CallbackQueryHandler(self._performance, pattern='update_performance'),
|
||||||
|
CallbackQueryHandler(self._count, pattern='update_count'),
|
||||||
|
CallbackQueryHandler(self._forcebuy_inline),
|
||||||
|
]
|
||||||
for handle in handles:
|
for handle in handles:
|
||||||
self._updater.dispatcher.add_handler(handle)
|
self._updater.dispatcher.add_handler(handle)
|
||||||
|
|
||||||
|
for callback in callbacks:
|
||||||
|
self._updater.dispatcher.add_handler(callback)
|
||||||
|
|
||||||
self._updater.start_polling(
|
self._updater.start_polling(
|
||||||
bootstrap_retries=-1,
|
bootstrap_retries=-1,
|
||||||
timeout=30,
|
timeout=30,
|
||||||
@ -177,11 +194,6 @@ class Telegram(RPCHandler):
|
|||||||
[h.command for h in handles]
|
[h.command for h in handles]
|
||||||
)
|
)
|
||||||
|
|
||||||
self._current_callback_query_handler: Optional[CallbackQueryHandler] = None
|
|
||||||
self._callback_query_handlers = {
|
|
||||||
'forcebuy': CallbackQueryHandler(self._forcebuy_inline)
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanup(self) -> None:
|
def cleanup(self) -> None:
|
||||||
"""
|
"""
|
||||||
Stops all running telegram threads.
|
Stops all running telegram threads.
|
||||||
@ -409,7 +421,9 @@ class Telegram(RPCHandler):
|
|||||||
# insert separators line between Total
|
# insert separators line between Total
|
||||||
lines = message.split("\n")
|
lines = message.split("\n")
|
||||||
message = "\n".join(lines[:-1] + [lines[1]] + [lines[-1]])
|
message = "\n".join(lines[:-1] + [lines[1]] + [lines[-1]])
|
||||||
self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML)
|
self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML,
|
||||||
|
reload_able=True, callback_path="update_status_table",
|
||||||
|
query=update.callback_query)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
|
||||||
@ -447,7 +461,8 @@ class Telegram(RPCHandler):
|
|||||||
],
|
],
|
||||||
tablefmt='simple')
|
tablefmt='simple')
|
||||||
message = f'<b>Daily Profit over the last {timescale} days</b>:\n<pre>{stats_tab}</pre>'
|
message = f'<b>Daily Profit over the last {timescale} days</b>:\n<pre>{stats_tab}</pre>'
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
self._send_msg(message, parse_mode=ParseMode.HTML, reload_able=True,
|
||||||
|
callback_path="update_daily", query=update.callback_query)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
|
||||||
@ -519,7 +534,8 @@ class Telegram(RPCHandler):
|
|||||||
if stats['closed_trade_count'] > 0:
|
if stats['closed_trade_count'] > 0:
|
||||||
markdown_msg += (f"\n*Avg. Duration:* `{avg_duration}`\n"
|
markdown_msg += (f"\n*Avg. Duration:* `{avg_duration}`\n"
|
||||||
f"*Best Performing:* `{best_pair}: {best_rate:.2f}%`")
|
f"*Best Performing:* `{best_pair}: {best_rate:.2f}%`")
|
||||||
self._send_msg(markdown_msg)
|
self._send_msg(markdown_msg, reload_able=True, callback_path="update_profit",
|
||||||
|
query=update.callback_query)
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _stats(self, update: Update, context: CallbackContext) -> None:
|
def _stats(self, update: Update, context: CallbackContext) -> None:
|
||||||
@ -606,7 +622,8 @@ class Telegram(RPCHandler):
|
|||||||
f"\t`{result['stake']}: {result['total']: .8f}`\n"
|
f"\t`{result['stake']}: {result['total']: .8f}`\n"
|
||||||
f"\t`{result['symbol']}: "
|
f"\t`{result['symbol']}: "
|
||||||
f"{round_coin_value(result['value'], result['symbol'], False)}`\n")
|
f"{round_coin_value(result['value'], result['symbol'], False)}`\n")
|
||||||
self._send_msg(output)
|
self._send_msg(output, reload_able=True, callback_path="update_balance",
|
||||||
|
query=update.callback_query)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
|
||||||
@ -713,10 +730,10 @@ class Telegram(RPCHandler):
|
|||||||
self._forcebuy_action(pair, price)
|
self._forcebuy_action(pair, price)
|
||||||
else:
|
else:
|
||||||
whitelist = self._rpc._rpc_whitelist()['whitelist']
|
whitelist = self._rpc._rpc_whitelist()['whitelist']
|
||||||
pairs = [InlineKeyboardButton(pair, callback_data=pair) for pair in whitelist]
|
pairs = [InlineKeyboardButton(text=pair, callback_data=pair) for pair in whitelist]
|
||||||
self._send_inline_msg("Which pair?",
|
|
||||||
keyboard=self._layout_inline_keyboard(pairs),
|
self._send_msg(msg="Which pair?",
|
||||||
callback_query_handler='forcebuy')
|
keyboard=self._layout_inline_keyboard(pairs))
|
||||||
|
|
||||||
@authorized_only
|
@authorized_only
|
||||||
def _trades(self, update: Update, context: CallbackContext) -> None:
|
def _trades(self, update: Update, context: CallbackContext) -> None:
|
||||||
@ -800,7 +817,9 @@ class Telegram(RPCHandler):
|
|||||||
else:
|
else:
|
||||||
output += stat_line
|
output += stat_line
|
||||||
|
|
||||||
self._send_msg(output, parse_mode=ParseMode.HTML)
|
self._send_msg(output, parse_mode=ParseMode.HTML,
|
||||||
|
reload_able=True, callback_path="update_performance",
|
||||||
|
query=update.callback_query)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
|
||||||
@ -820,7 +839,9 @@ class Telegram(RPCHandler):
|
|||||||
tablefmt='simple')
|
tablefmt='simple')
|
||||||
message = "<pre>{}</pre>".format(message)
|
message = "<pre>{}</pre>".format(message)
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
self._send_msg(message, parse_mode=ParseMode.HTML)
|
self._send_msg(message, parse_mode=ParseMode.HTML,
|
||||||
|
reload_able=True, callback_path="update_count",
|
||||||
|
query=update.callback_query)
|
||||||
except RPCException as e:
|
except RPCException as e:
|
||||||
self._send_msg(str(e))
|
self._send_msg(str(e))
|
||||||
|
|
||||||
@ -1052,29 +1073,42 @@ class Telegram(RPCHandler):
|
|||||||
f"*Current state:* `{val['state']}`"
|
f"*Current state:* `{val['state']}`"
|
||||||
)
|
)
|
||||||
|
|
||||||
def _send_inline_msg(self, msg: str, callback_query_handler,
|
def _update_msg(self, query: CallbackQuery, msg: str, callback_path: str = "",
|
||||||
parse_mode: str = ParseMode.MARKDOWN, disable_notification: bool = False,
|
reload_able: bool = False, parse_mode: str = ParseMode.MARKDOWN) -> None:
|
||||||
keyboard: List[List[InlineKeyboardButton]] = None, ) -> None:
|
if reload_able:
|
||||||
"""
|
reply_markup = InlineKeyboardMarkup([
|
||||||
Send given markdown message
|
[InlineKeyboardButton("Refresh", callback_data=callback_path)],
|
||||||
:param msg: message
|
])
|
||||||
:param bot: alternative bot
|
else:
|
||||||
:param parse_mode: telegram parse mode
|
reply_markup = InlineKeyboardMarkup([[]])
|
||||||
:return: None
|
msg += "\nUpdated: {}".format(datetime.now().ctime())
|
||||||
"""
|
if not query.message:
|
||||||
if self._current_callback_query_handler:
|
return
|
||||||
self._updater.dispatcher.remove_handler(self._current_callback_query_handler)
|
chat_id = query.message.chat_id
|
||||||
self._current_callback_query_handler = self._callback_query_handlers[callback_query_handler]
|
message_id = query.message.message_id
|
||||||
self._updater.dispatcher.add_handler(self._current_callback_query_handler)
|
|
||||||
|
|
||||||
self._send_msg(msg, parse_mode, disable_notification,
|
try:
|
||||||
cast(List[List[Union[str, KeyboardButton, InlineKeyboardButton]]], keyboard),
|
self._updater.bot.edit_message_text(
|
||||||
reply_markup=InlineKeyboardMarkup)
|
chat_id=chat_id,
|
||||||
|
message_id=message_id,
|
||||||
|
text=msg,
|
||||||
|
parse_mode=parse_mode,
|
||||||
|
reply_markup=reply_markup
|
||||||
|
)
|
||||||
|
except BadRequest as e:
|
||||||
|
if 'not modified' in e.message.lower():
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logger.warning('TelegramError: %s', e.message)
|
||||||
|
except TelegramError as telegram_err:
|
||||||
|
logger.warning('TelegramError: %s! Giving up on that message.', telegram_err.message)
|
||||||
|
|
||||||
def _send_msg(self, msg: str, parse_mode: str = ParseMode.MARKDOWN,
|
def _send_msg(self, msg: str, parse_mode: str = ParseMode.MARKDOWN,
|
||||||
disable_notification: bool = False,
|
disable_notification: bool = False,
|
||||||
keyboard: List[List[Union[str, KeyboardButton, InlineKeyboardButton]]] = None,
|
keyboard: List[List[InlineKeyboardButton]] = None,
|
||||||
reply_markup=ReplyKeyboardMarkup) -> None:
|
callback_path: str = "",
|
||||||
|
reload_able: bool = False,
|
||||||
|
query: Optional[CallbackQuery] = None) -> None:
|
||||||
"""
|
"""
|
||||||
Send given markdown message
|
Send given markdown message
|
||||||
:param msg: message
|
:param msg: message
|
||||||
@ -1082,9 +1116,19 @@ class Telegram(RPCHandler):
|
|||||||
:param parse_mode: telegram parse mode
|
:param parse_mode: telegram parse mode
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
if keyboard is None:
|
reply_markup: Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]
|
||||||
keyboard = self._keyboard
|
if query:
|
||||||
reply_markup = reply_markup(keyboard, resize_keyboard=True)
|
self._update_msg(query=query, msg=msg, parse_mode=parse_mode,
|
||||||
|
callback_path=callback_path, reload_able=reload_able)
|
||||||
|
return
|
||||||
|
if reload_able and self._config['telegram'].get('reload', True):
|
||||||
|
reply_markup = InlineKeyboardMarkup([
|
||||||
|
[InlineKeyboardButton("Refresh", callback_data=callback_path)]])
|
||||||
|
else:
|
||||||
|
if keyboard is not None:
|
||||||
|
reply_markup = InlineKeyboardMarkup(keyboard, resize_keyboard=True)
|
||||||
|
else:
|
||||||
|
reply_markup = ReplyKeyboardMarkup(self._keyboard, resize_keyboard=True)
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
self._updater.bot.send_message(
|
self._updater.bot.send_message(
|
||||||
|
@ -13,7 +13,7 @@ from unittest.mock import ANY, MagicMock
|
|||||||
import arrow
|
import arrow
|
||||||
import pytest
|
import pytest
|
||||||
from telegram import Chat, Message, ReplyKeyboardMarkup, Update
|
from telegram import Chat, Message, ReplyKeyboardMarkup, Update
|
||||||
from telegram.error import NetworkError
|
from telegram.error import BadRequest, NetworkError, TelegramError
|
||||||
|
|
||||||
from freqtrade import __version__
|
from freqtrade import __version__
|
||||||
from freqtrade.constants import CANCEL_REASON
|
from freqtrade.constants import CANCEL_REASON
|
||||||
@ -25,8 +25,8 @@ from freqtrade.loggers import setup_logging
|
|||||||
from freqtrade.persistence import PairLocks, Trade
|
from freqtrade.persistence import PairLocks, Trade
|
||||||
from freqtrade.rpc import RPC
|
from freqtrade.rpc import RPC
|
||||||
from freqtrade.rpc.telegram import Telegram, authorized_only
|
from freqtrade.rpc.telegram import Telegram, authorized_only
|
||||||
from tests.conftest import (create_mock_trades, get_patched_freqtradebot, log_has, patch_exchange,
|
from tests.conftest import (create_mock_trades, get_patched_freqtradebot, log_has, log_has_re,
|
||||||
patch_get_signal, patch_whitelist)
|
patch_exchange, patch_get_signal, patch_whitelist)
|
||||||
|
|
||||||
|
|
||||||
class DummyCls(Telegram):
|
class DummyCls(Telegram):
|
||||||
@ -55,14 +55,6 @@ class DummyCls(Telegram):
|
|||||||
raise Exception('test')
|
raise Exception('test')
|
||||||
|
|
||||||
|
|
||||||
def get_telegram_testobject_with_inline(mocker, default_conf, mock=True, ftbot=None):
|
|
||||||
inline_msg_mock = MagicMock()
|
|
||||||
telegram, ftbot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
|
||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._send_inline_msg', inline_msg_mock)
|
|
||||||
|
|
||||||
return telegram, ftbot, msg_mock, inline_msg_mock
|
|
||||||
|
|
||||||
|
|
||||||
def get_telegram_testobject(mocker, default_conf, mock=True, ftbot=None):
|
def get_telegram_testobject(mocker, default_conf, mock=True, ftbot=None):
|
||||||
msg_mock = MagicMock()
|
msg_mock = MagicMock()
|
||||||
if mock:
|
if mock:
|
||||||
@ -920,8 +912,8 @@ def test_forcebuy_no_pair(default_conf, update, mocker) -> None:
|
|||||||
fbuy_mock = MagicMock(return_value=None)
|
fbuy_mock = MagicMock(return_value=None)
|
||||||
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
|
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
|
||||||
|
|
||||||
telegram, freqtradebot, _, inline_msg_mock = get_telegram_testobject_with_inline(mocker,
|
telegram, freqtradebot, msg_mock = get_telegram_testobject(mocker, default_conf)
|
||||||
default_conf)
|
|
||||||
patch_get_signal(freqtradebot, (True, False))
|
patch_get_signal(freqtradebot, (True, False))
|
||||||
|
|
||||||
context = MagicMock()
|
context = MagicMock()
|
||||||
@ -929,10 +921,10 @@ def test_forcebuy_no_pair(default_conf, update, mocker) -> None:
|
|||||||
telegram._forcebuy(update=update, context=context)
|
telegram._forcebuy(update=update, context=context)
|
||||||
|
|
||||||
assert fbuy_mock.call_count == 0
|
assert fbuy_mock.call_count == 0
|
||||||
assert inline_msg_mock.call_count == 1
|
assert msg_mock.call_count == 1
|
||||||
assert inline_msg_mock.call_args_list[0][0][0] == 'Which pair?'
|
assert msg_mock.call_args_list[0][1]['msg'] == 'Which pair?'
|
||||||
assert inline_msg_mock.call_args_list[0][1]['callback_query_handler'] == 'forcebuy'
|
# assert msg_mock.call_args_list[0][1]['callback_query_handler'] == 'forcebuy'
|
||||||
keyboard = inline_msg_mock.call_args_list[0][1]['keyboard']
|
keyboard = msg_mock.call_args_list[0][1]['keyboard']
|
||||||
assert reduce(lambda acc, x: acc + len(x), keyboard, 0) == 4
|
assert reduce(lambda acc, x: acc + len(x), keyboard, 0) == 4
|
||||||
update = MagicMock()
|
update = MagicMock()
|
||||||
update.callback_query = MagicMock()
|
update.callback_query = MagicMock()
|
||||||
@ -1569,7 +1561,7 @@ def test__sell_emoji(default_conf, mocker, msg, expected):
|
|||||||
assert telegram._get_sell_emoji(msg) == expected
|
assert telegram._get_sell_emoji(msg) == expected
|
||||||
|
|
||||||
|
|
||||||
def test__send_msg(default_conf, mocker) -> None:
|
def test_telegram__send_msg(default_conf, mocker, caplog) -> None:
|
||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||||
bot = MagicMock()
|
bot = MagicMock()
|
||||||
telegram, _, _ = get_telegram_testobject(mocker, default_conf, mock=False)
|
telegram, _, _ = get_telegram_testobject(mocker, default_conf, mock=False)
|
||||||
@ -1580,6 +1572,28 @@ def test__send_msg(default_conf, mocker) -> None:
|
|||||||
telegram._send_msg('test')
|
telegram._send_msg('test')
|
||||||
assert len(bot.method_calls) == 1
|
assert len(bot.method_calls) == 1
|
||||||
|
|
||||||
|
# Test update
|
||||||
|
query = MagicMock()
|
||||||
|
telegram._send_msg('test', callback_path="DeadBeef", query=query, reload_able=True)
|
||||||
|
edit_message_text = telegram._updater.bot.edit_message_text
|
||||||
|
assert edit_message_text.call_count == 1
|
||||||
|
assert "Updated: " in edit_message_text.call_args_list[0][1]['text']
|
||||||
|
|
||||||
|
telegram._updater.bot.edit_message_text = MagicMock(side_effect=BadRequest("not modified"))
|
||||||
|
telegram._send_msg('test', callback_path="DeadBeef", query=query)
|
||||||
|
assert telegram._updater.bot.edit_message_text.call_count == 1
|
||||||
|
assert not log_has_re(r"TelegramError: .*", caplog)
|
||||||
|
|
||||||
|
telegram._updater.bot.edit_message_text = MagicMock(side_effect=BadRequest(""))
|
||||||
|
telegram._send_msg('test2', callback_path="DeadBeef", query=query)
|
||||||
|
assert telegram._updater.bot.edit_message_text.call_count == 1
|
||||||
|
assert log_has_re(r"TelegramError: .*", caplog)
|
||||||
|
|
||||||
|
telegram._updater.bot.edit_message_text = MagicMock(side_effect=TelegramError("DeadBEEF"))
|
||||||
|
telegram._send_msg('test3', callback_path="DeadBeef", query=query)
|
||||||
|
|
||||||
|
assert log_has_re(r"TelegramError: DeadBEEF! Giving up.*", caplog)
|
||||||
|
|
||||||
|
|
||||||
def test__send_msg_network_error(default_conf, mocker, caplog) -> None:
|
def test__send_msg_network_error(default_conf, mocker, caplog) -> None:
|
||||||
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock())
|
||||||
|
Loading…
Reference in New Issue
Block a user