Merge pull request #2211 from freqtrade/dependabot/pip/develop/python-telegram-bot-12.0.0

Bump python-telegram-bot from 11.1.0 to 12.0.0
This commit is contained in:
hroff-1902 2019-09-04 10:44:11 +03:00 committed by GitHub
commit 74578b8752
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 158 additions and 132 deletions

View File

@ -4,12 +4,12 @@
This module manage Telegram communication
"""
import logging
from typing import Any, Callable, Dict, List
from typing import Any, Callable, Dict
from tabulate import tabulate
from telegram import Bot, ParseMode, ReplyKeyboardMarkup, Update
from telegram import ParseMode, ReplyKeyboardMarkup, Update
from telegram.error import NetworkError, TelegramError
from telegram.ext import CommandHandler, Updater
from telegram.ext import CommandHandler, Updater, CallbackContext
from freqtrade.__init__ import __version__
from freqtrade.rpc import RPC, RPCException, RPCMessageType
@ -31,7 +31,7 @@ def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]:
"""
def wrapper(self, *args, **kwargs):
""" Decorator logic """
update = kwargs.get('update') or args[1]
update = kwargs.get('update') or args[0]
# Reject unauthorized messages
chat_id = int(self._config['telegram']['chat_id'])
@ -79,7 +79,8 @@ class Telegram(RPC):
registers all known command handlers
and starts polling for message updates
"""
self._updater = Updater(token=self._config['telegram']['token'], workers=0)
self._updater = Updater(token=self._config['telegram']['token'], workers=0,
use_context=True)
# Register command handler and start telegram message polling
handles = [
@ -96,7 +97,7 @@ class Telegram(RPC):
CommandHandler('reload_conf', self._reload_conf),
CommandHandler('stopbuy', self._stopbuy),
CommandHandler('whitelist', self._whitelist),
CommandHandler('blacklist', self._blacklist, pass_args=True),
CommandHandler('blacklist', self._blacklist),
CommandHandler('edge', self._edge),
CommandHandler('help', self._help),
CommandHandler('version', self._version),
@ -175,7 +176,7 @@ class Telegram(RPC):
self._send_msg(message)
@authorized_only
def _status(self, bot: Bot, update: Update) -> None:
def _status(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /status.
Returns the current TradeThread status
@ -184,11 +185,8 @@ class Telegram(RPC):
:return: None
"""
# Check if additional parameters are passed
params = update.message.text.replace('/status', '').split(' ') \
if update.message.text else []
if 'table' in params:
self._status_table(bot, update)
if 'table' in context.args:
self._status_table(update, context)
return
try:
@ -221,13 +219,13 @@ class Telegram(RPC):
messages.append("\n".join([l for l in lines if l]).format(**r))
for msg in messages:
self._send_msg(msg, bot=bot)
self._send_msg(msg)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _status_table(self, bot: Bot, update: Update) -> None:
def _status_table(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /status table.
Returns the current TradeThread status in table format
@ -240,10 +238,10 @@ class Telegram(RPC):
message = tabulate(df_statuses, headers='keys', tablefmt='simple')
self._send_msg(f"<pre>{message}</pre>", parse_mode=ParseMode.HTML)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _daily(self, bot: Bot, update: Update) -> None:
def _daily(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /daily <n>
Returns a daily profit (in BTC) over the last n days.
@ -254,8 +252,8 @@ class Telegram(RPC):
stake_cur = self._config['stake_currency']
fiat_disp_cur = self._config.get('fiat_display_currency', '')
try:
timescale = int(update.message.text.replace('/daily', '').strip())
except (TypeError, ValueError):
timescale = int(context.args[0])
except (TypeError, ValueError, IndexError):
timescale = 7
try:
stats = self._rpc_daily_profit(
@ -272,12 +270,12 @@ class Telegram(RPC):
],
tablefmt='simple')
message = f'<b>Daily Profit over the last {timescale} days</b>:\n<pre>{stats_tab}</pre>'
self._send_msg(message, bot=bot, parse_mode=ParseMode.HTML)
self._send_msg(message, parse_mode=ParseMode.HTML)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _profit(self, bot: Bot, update: Update) -> None:
def _profit(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /profit.
Returns a cumulative profit statistics.
@ -317,12 +315,12 @@ class Telegram(RPC):
f"*Latest Trade opened:* `{latest_trade_date}`\n" \
f"*Avg. Duration:* `{avg_duration}`\n" \
f"*Best Performing:* `{best_pair}: {best_rate:.2f}%`"
self._send_msg(markdown_msg, bot=bot)
self._send_msg(markdown_msg)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _balance(self, bot: Bot, update: Update) -> None:
def _balance(self, update: Update, context: CallbackContext) -> None:
""" Handler for /balance """
try:
result = self._rpc_balance(self._config.get('fiat_display_currency', ''))
@ -339,7 +337,7 @@ class Telegram(RPC):
# Handle overflowing messsage length
if len(output + curr_output) >= MAX_TELEGRAM_MESSAGE_LENGTH:
self._send_msg(output, bot=bot)
self._send_msg(output)
output = curr_output
else:
output += curr_output
@ -347,12 +345,12 @@ class Telegram(RPC):
output += "\n*Estimated Value*:\n" \
"\t`BTC: {total: .8f}`\n" \
"\t`{symbol}: {value: .2f}`\n".format(**result)
self._send_msg(output, bot=bot)
self._send_msg(output)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _start(self, bot: Bot, update: Update) -> None:
def _start(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /start.
Starts TradeThread
@ -361,10 +359,10 @@ class Telegram(RPC):
:return: None
"""
msg = self._rpc_start()
self._send_msg('Status: `{status}`'.format(**msg), bot=bot)
self._send_msg('Status: `{status}`'.format(**msg))
@authorized_only
def _stop(self, bot: Bot, update: Update) -> None:
def _stop(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /stop.
Stops TradeThread
@ -373,10 +371,10 @@ class Telegram(RPC):
:return: None
"""
msg = self._rpc_stop()
self._send_msg('Status: `{status}`'.format(**msg), bot=bot)
self._send_msg('Status: `{status}`'.format(**msg))
@authorized_only
def _reload_conf(self, bot: Bot, update: Update) -> None:
def _reload_conf(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /reload_conf.
Triggers a config file reload
@ -385,10 +383,10 @@ class Telegram(RPC):
:return: None
"""
msg = self._rpc_reload_conf()
self._send_msg('Status: `{status}`'.format(**msg), bot=bot)
self._send_msg('Status: `{status}`'.format(**msg))
@authorized_only
def _stopbuy(self, bot: Bot, update: Update) -> None:
def _stopbuy(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /stop_buy.
Sets max_open_trades to 0 and gracefully sells all open trades
@ -397,10 +395,10 @@ class Telegram(RPC):
:return: None
"""
msg = self._rpc_stopbuy()
self._send_msg('Status: `{status}`'.format(**msg), bot=bot)
self._send_msg('Status: `{status}`'.format(**msg))
@authorized_only
def _forcesell(self, bot: Bot, update: Update) -> None:
def _forcesell(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /forcesell <id>.
Sells the given trade at current price
@ -409,16 +407,16 @@ class Telegram(RPC):
:return: None
"""
trade_id = update.message.text.replace('/forcesell', '').strip()
trade_id = context.args[0] if len(context.args) > 0 else None
try:
msg = self._rpc_forcesell(trade_id)
self._send_msg('Forcesell Result: `{result}`'.format(**msg), bot=bot)
self._send_msg('Forcesell Result: `{result}`'.format(**msg))
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _forcebuy(self, bot: Bot, update: Update) -> None:
def _forcebuy(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /forcebuy <asset> <price>.
Buys a pair trade at the given or current price
@ -427,16 +425,15 @@ class Telegram(RPC):
:return: None
"""
message = update.message.text.replace('/forcebuy', '').strip().split()
pair = message[0]
price = float(message[1]) if len(message) > 1 else None
pair = context.args[0]
price = float(context.args[1]) if len(context.args) > 1 else None
try:
self._rpc_forcebuy(pair, price)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _performance(self, bot: Bot, update: Update) -> None:
def _performance(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /performance.
Shows a performance statistic from finished trades
@ -455,10 +452,10 @@ class Telegram(RPC):
message = '<b>Performance:</b>\n{}'.format(stats)
self._send_msg(message, parse_mode=ParseMode.HTML)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _count(self, bot: Bot, update: Update) -> None:
def _count(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /count.
Returns the number of trades running
@ -475,10 +472,10 @@ class Telegram(RPC):
logger.debug(message)
self._send_msg(message, parse_mode=ParseMode.HTML)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _whitelist(self, bot: Bot, update: Update) -> None:
def _whitelist(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /whitelist
Shows the currently active whitelist
@ -492,17 +489,17 @@ class Telegram(RPC):
logger.debug(message)
self._send_msg(message)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _blacklist(self, bot: Bot, update: Update, args: List[str]) -> None:
def _blacklist(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /blacklist
Shows the currently active blacklist
"""
try:
blacklist = self._rpc_blacklist(args)
blacklist = self._rpc_blacklist(context.args)
message = f"Blacklist contains {blacklist['length']} pairs\n"
message += f"`{', '.join(blacklist['blacklist'])}`"
@ -510,10 +507,10 @@ class Telegram(RPC):
logger.debug(message)
self._send_msg(message)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _edge(self, bot: Bot, update: Update) -> None:
def _edge(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /edge
Shows information related to Edge
@ -522,12 +519,12 @@ class Telegram(RPC):
edge_pairs = self._rpc_edge()
edge_pairs_tab = tabulate(edge_pairs, headers='keys', tablefmt='simple')
message = f'<b>Edge only validated following pairs:</b>\n<pre>{edge_pairs_tab}</pre>'
self._send_msg(message, bot=bot, parse_mode=ParseMode.HTML)
self._send_msg(message, parse_mode=ParseMode.HTML)
except RPCException as e:
self._send_msg(str(e), bot=bot)
self._send_msg(str(e))
@authorized_only
def _help(self, bot: Bot, update: Update) -> None:
def _help(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /help.
Show commands of the bot
@ -559,10 +556,10 @@ class Telegram(RPC):
"*/help:* `This help message`\n" \
"*/version:* `Show version`"
self._send_msg(message, bot=bot)
self._send_msg(message)
@authorized_only
def _version(self, bot: Bot, update: Update) -> None:
def _version(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /version.
Show version information
@ -570,10 +567,9 @@ class Telegram(RPC):
:param update: message update
:return: None
"""
self._send_msg('*Version:* `{}`'.format(__version__), bot=bot)
self._send_msg('*Version:* `{}`'.format(__version__))
def _send_msg(self, msg: str, bot: Bot = None,
parse_mode: ParseMode = ParseMode.MARKDOWN) -> None:
def _send_msg(self, msg: str, parse_mode: ParseMode = ParseMode.MARKDOWN) -> None:
"""
Send given markdown message
:param msg: message
@ -581,7 +577,6 @@ class Telegram(RPC):
:param parse_mode: telegram parse mode
:return: None
"""
bot = bot or self._updater.bot
keyboard = [['/daily', '/profit', '/balance'],
['/status', '/status table', '/performance'],
@ -591,7 +586,7 @@ class Telegram(RPC):
try:
try:
bot.send_message(
self._updater.bot.send_message(
self._config['telegram']['chat_id'],
text=msg,
parse_mode=parse_mode,
@ -604,7 +599,7 @@ class Telegram(RPC):
'Telegram NetworkError: %s! Trying one more time.',
network_err.message
)
bot.send_message(
self._updater.bot.send_message(
self._config['telegram']['chat_id'],
text=msg,
parse_mode=parse_mode,

View File

@ -100,7 +100,7 @@ def test_authorized_only(default_conf, mocker, caplog) -> None:
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_handler(bot=MagicMock(), update=update)
dummy.dummy_handler(update=update, context=MagicMock())
assert dummy.state['called'] is True
assert log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
assert not log_has('Rejected unauthorized message from: 0', caplog)
@ -117,7 +117,7 @@ def test_authorized_only_unauthorized(default_conf, mocker, caplog) -> None:
bot = FreqtradeBot(default_conf)
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_handler(bot=MagicMock(), update=update)
dummy.dummy_handler(update=update, context=MagicMock())
assert dummy.state['called'] is False
assert not log_has('Executing handler: dummy_handler for chat_id: 3735928559', caplog)
assert log_has('Rejected unauthorized message from: 3735928559', caplog)
@ -136,7 +136,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None:
patch_get_signal(bot, (True, False))
dummy = DummyCls(bot)
dummy.dummy_exception(bot=MagicMock(), update=update)
dummy.dummy_exception(update=update, context=MagicMock())
assert dummy.state['called'] is False
assert not log_has('Executing handler: dummy_handler for chat_id: 0', caplog)
assert not log_has('Rejected unauthorized message from: 0', caplog)
@ -194,12 +194,13 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
for _ in range(3):
freqtradebot.create_trades()
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
assert msg_mock.call_count == 1
update.message.text = MagicMock()
update.message.text.replace = MagicMock(return_value='table 2 3')
telegram._status(bot=MagicMock(), update=update)
context = MagicMock()
# /status table 2 3
context.args = ["table", "2", "3"]
telegram._status(update=update, context=context)
assert status_table.call_count == 1
@ -228,13 +229,13 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
freqtradebot.state = State.STOPPED
# Status is also enabled when stopped
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@ -242,7 +243,7 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
# Create some test data
freqtradebot.create_trades()
# Trigger status while we have a fulfilled order for the open trade
telegram._status(bot=MagicMock(), update=update)
telegram._status(update=update, context=MagicMock())
# close_rate should not be included in the message as the trade is not closed
# and no line should be empty
@ -280,13 +281,13 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
freqtradebot.state = State.STOPPED
# Status table is also enabled when stopped
telegram._status_table(bot=MagicMock(), update=update)
telegram._status_table(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active order' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
telegram._status_table(bot=MagicMock(), update=update)
telegram._status_table(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no active order' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@ -294,7 +295,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
# Create some test data
freqtradebot.create_trades()
telegram._status_table(bot=MagicMock(), update=update)
telegram._status_table(update=update, context=MagicMock())
text = re.sub('</?pre>', '', msg_mock.call_args_list[-1][0][0])
line = text.split("\n")
@ -346,8 +347,10 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
trade.is_open = False
# Try valid data
update.message.text = '/daily 2'
telegram._daily(bot=MagicMock(), update=update)
# /daily 2
context = MagicMock()
context.args = ["2"]
telegram._daily(update=update, context=context)
assert msg_mock.call_count == 1
assert 'Daily' in msg_mock.call_args_list[0][0][0]
assert str(datetime.utcnow().date()) in msg_mock.call_args_list[0][0][0]
@ -369,9 +372,10 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
trade.close_date = datetime.utcnow()
trade.is_open = False
update.message.text = '/daily 1'
telegram._daily(bot=MagicMock(), update=update)
# /daily 1
context = MagicMock()
context.args = ["1"]
telegram._daily(update=update, context=context)
assert str(' 0.00018651 BTC') in msg_mock.call_args_list[0][0][0]
assert str(' 2.798 USD') in msg_mock.call_args_list[0][0][0]
assert str(' 3 trades') in msg_mock.call_args_list[0][0][0]
@ -398,16 +402,20 @@ def test_daily_wrong_input(default_conf, update, ticker, mocker) -> None:
# Try invalid data
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/daily -2'
telegram._daily(bot=MagicMock(), update=update)
# /daily -2
context = MagicMock()
context.args = ["-2"]
telegram._daily(update=update, context=context)
assert msg_mock.call_count == 1
assert 'must be an integer greater than 0' in msg_mock.call_args_list[0][0][0]
# Try invalid data
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/daily today'
telegram._daily(bot=MagicMock(), update=update)
# /daily today
context = MagicMock()
context.args = ["today"]
telegram._daily(update=update, context=context)
assert str('Daily Profit over the last 7 days') in msg_mock.call_args_list[0][0][0]
@ -433,7 +441,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot)
telegram._profit(bot=MagicMock(), update=update)
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no closed trade' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@ -445,7 +453,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
# Simulate fulfilled LIMIT_BUY order for trade
trade.update(limit_buy_order)
telegram._profit(bot=MagicMock(), update=update)
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'no closed trade' in msg_mock.call_args_list[-1][0][0]
msg_mock.reset_mock()
@ -457,7 +465,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram._profit(bot=MagicMock(), update=update)
telegram._profit(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*ROI:* Close trades' in msg_mock.call_args_list[-1][0][0]
assert '∙ `0.00006217 BTC (6.20%)`' in msg_mock.call_args_list[-1][0][0]
@ -507,7 +515,7 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance) -> N
telegram = Telegram(freqtradebot)
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert '*BTC:*' in result
@ -536,7 +544,7 @@ def test_balance_handle_empty_response(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
freqtradebot.config['dry_run'] = False
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert 'All balances are zero.' in result
@ -557,7 +565,7 @@ def test_balance_handle_empty_response_dry(default_conf, update, mocker) -> None
telegram = Telegram(freqtradebot)
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
result = msg_mock.call_args_list[0][0][0]
assert msg_mock.call_count == 1
assert "Running in Dry Run, balances are not available." in result
@ -593,7 +601,7 @@ def test_balance_handle_too_large_response(default_conf, update, mocker) -> None
telegram = Telegram(freqtradebot)
telegram._balance(bot=MagicMock(), update=update)
telegram._balance(update=update, context=MagicMock())
assert msg_mock.call_count > 1
# Test if wrap happens around 4000 -
# and each single currency-output is around 120 characters long so we need
@ -615,7 +623,7 @@ def test_start_handle(default_conf, update, mocker) -> None:
freqtradebot.state = State.STOPPED
assert freqtradebot.state == State.STOPPED
telegram._start(bot=MagicMock(), update=update)
telegram._start(update=update, context=MagicMock())
assert freqtradebot.state == State.RUNNING
assert msg_mock.call_count == 1
@ -633,7 +641,7 @@ def test_start_handle_already_running(default_conf, update, mocker) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.state == State.RUNNING
telegram._start(bot=MagicMock(), update=update)
telegram._start(update=update, context=MagicMock())
assert freqtradebot.state == State.RUNNING
assert msg_mock.call_count == 1
assert 'already running' in msg_mock.call_args_list[0][0][0]
@ -652,7 +660,7 @@ def test_stop_handle(default_conf, update, mocker) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.state == State.RUNNING
telegram._stop(bot=MagicMock(), update=update)
telegram._stop(update=update, context=MagicMock())
assert freqtradebot.state == State.STOPPED
assert msg_mock.call_count == 1
assert 'stopping trader' in msg_mock.call_args_list[0][0][0]
@ -671,7 +679,7 @@ def test_stop_handle_already_stopped(default_conf, update, mocker) -> None:
freqtradebot.state = State.STOPPED
assert freqtradebot.state == State.STOPPED
telegram._stop(bot=MagicMock(), update=update)
telegram._stop(update=update, context=MagicMock())
assert freqtradebot.state == State.STOPPED
assert msg_mock.call_count == 1
assert 'already stopped' in msg_mock.call_args_list[0][0][0]
@ -689,7 +697,7 @@ def test_stopbuy_handle(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
assert freqtradebot.config['max_open_trades'] != 0
telegram._stopbuy(bot=MagicMock(), update=update)
telegram._stopbuy(update=update, context=MagicMock())
assert freqtradebot.config['max_open_trades'] == 0
assert msg_mock.call_count == 1
assert 'No more buy will occur from now. Run /reload_conf to reset.' \
@ -709,7 +717,7 @@ def test_reload_conf_handle(default_conf, update, mocker) -> None:
freqtradebot.state = State.RUNNING
assert freqtradebot.state == State.RUNNING
telegram._reload_conf(bot=MagicMock(), update=update)
telegram._reload_conf(update=update, context=MagicMock())
assert freqtradebot.state == State.RELOAD_CONF
assert msg_mock.call_count == 1
assert 'reloading config' in msg_mock.call_args_list[0][0][0]
@ -742,8 +750,10 @@ def test_forcesell_handle(default_conf, update, ticker, fee,
# Increase the price and sell it
mocker.patch('freqtrade.exchange.Exchange.get_ticker', ticker_sell_up)
update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forcesell(update=update, context=context)
assert rpc_mock.call_count == 2
last_msg = rpc_mock.call_args_list[-1][0][0]
@ -796,8 +806,10 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee,
trade = Trade.query.first()
assert trade
update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forcesell(update=update, context=context)
assert rpc_mock.call_count == 2
@ -842,8 +854,10 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker
freqtradebot.create_trades()
rpc_mock.reset_mock()
update.message.text = '/forcesell all'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell all
context = MagicMock()
context.args = ["all"]
telegram._forcesell(update=update, context=context)
assert rpc_mock.call_count == 4
msg = rpc_mock.call_args_list[0][0][0]
@ -882,24 +896,29 @@ def test_forcesell_handle_invalid(default_conf, update, mocker) -> None:
# Trader is not running
freqtradebot.state = State.STOPPED
update.message.text = '/forcesell 1'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 1
context = MagicMock()
context.args = ["1"]
telegram._forcesell(update=update, context=context)
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
# No argument
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/forcesell'
telegram._forcesell(bot=MagicMock(), update=update)
context = MagicMock()
context.args = []
telegram._forcesell(update=update, context=context)
assert msg_mock.call_count == 1
assert 'invalid argument' in msg_mock.call_args_list[0][0][0]
# Invalid argument
msg_mock.reset_mock()
freqtradebot.state = State.RUNNING
update.message.text = '/forcesell 123456'
telegram._forcesell(bot=MagicMock(), update=update)
# /forcesell 123456
context = MagicMock()
context.args = ["123456"]
telegram._forcesell(update=update, context=context)
assert msg_mock.call_count == 1
assert 'invalid argument' in msg_mock.call_args_list[0][0][0]
@ -921,8 +940,10 @@ def test_forcebuy_handle(default_conf, update, markets, mocker) -> None:
patch_get_signal(freqtradebot, (True, False))
telegram = Telegram(freqtradebot)
update.message.text = '/forcebuy ETH/BTC'
telegram._forcebuy(bot=MagicMock(), update=update)
# /forcebuy ETH/BTC
context = MagicMock()
context.args = ["ETH/BTC"]
telegram._forcebuy(update=update, context=context)
assert fbuy_mock.call_count == 1
assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
@ -931,8 +952,10 @@ def test_forcebuy_handle(default_conf, update, markets, mocker) -> None:
# Reset and retry with specified price
fbuy_mock = MagicMock(return_value=None)
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
update.message.text = '/forcebuy ETH/BTC 0.055'
telegram._forcebuy(bot=MagicMock(), update=update)
# /forcebuy ETH/BTC 0.055
context = MagicMock()
context.args = ["ETH/BTC", "0.055"]
telegram._forcebuy(update=update, context=context)
assert fbuy_mock.call_count == 1
assert fbuy_mock.call_args_list[0][0][0] == 'ETH/BTC'
@ -955,7 +978,7 @@ def test_forcebuy_handle_exception(default_conf, update, markets, mocker) -> Non
telegram = Telegram(freqtradebot)
update.message.text = '/forcebuy ETH/Nonepair'
telegram._forcebuy(bot=MagicMock(), update=update)
telegram._forcebuy(update=update, context=MagicMock())
assert rpc_mock.call_count == 1
assert rpc_mock.call_args_list[0][0][0] == 'Forcebuy not enabled.'
@ -995,7 +1018,7 @@ def test_performance_handle(default_conf, update, ticker, fee,
trade.close_date = datetime.utcnow()
trade.is_open = False
telegram._performance(bot=MagicMock(), update=update)
telegram._performance(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'Performance' in msg_mock.call_args_list[0][0][0]
assert '<code>ETH/BTC\t6.20% (1)</code>' in msg_mock.call_args_list[0][0][0]
@ -1021,7 +1044,7 @@ def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> Non
telegram = Telegram(freqtradebot)
freqtradebot.state = State.STOPPED
telegram._count(bot=MagicMock(), update=update)
telegram._count(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert 'not running' in msg_mock.call_args_list[0][0][0]
msg_mock.reset_mock()
@ -1030,7 +1053,7 @@ def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> Non
# Create some test data
freqtradebot.create_trades()
msg_mock.reset_mock()
telegram._count(bot=MagicMock(), update=update)
telegram._count(update=update, context=MagicMock())
msg = '<pre> current max total stake\n--------- ----- -------------\n' \
' 1 {} {}</pre>'\
@ -1052,7 +1075,7 @@ def test_whitelist_static(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._whitelist(bot=MagicMock(), update=update)
telegram._whitelist(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert ('Using whitelist `StaticPairList` with 4 pairs\n`ETH/BTC, LTC/BTC, XRP/BTC, NEO/BTC`'
in msg_mock.call_args_list[0][0][0])
@ -1073,7 +1096,7 @@ def test_whitelist_dynamic(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._whitelist(bot=MagicMock(), update=update)
telegram._whitelist(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert ('Using whitelist `VolumePairList` with 4 pairs\n`ETH/BTC, LTC/BTC, XRP/BTC, NEO/BTC`'
in msg_mock.call_args_list[0][0][0])
@ -1090,13 +1113,17 @@ def test_blacklist_static(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._blacklist(bot=MagicMock(), update=update, args=[])
telegram._blacklist(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert ("Blacklist contains 2 pairs\n`DOGE/BTC, HOT/BTC`"
in msg_mock.call_args_list[0][0][0])
msg_mock.reset_mock()
telegram._blacklist(bot=MagicMock(), update=update, args=["ETH/BTC"])
# /blacklist ETH/BTC
context = MagicMock()
context.args = ["ETH/BTC"]
telegram._blacklist(update=update, context=context)
assert msg_mock.call_count == 1
assert ("Blacklist contains 3 pairs\n`DOGE/BTC, HOT/BTC, ETH/BTC`"
in msg_mock.call_args_list[0][0][0])
@ -1115,7 +1142,7 @@ def test_edge_disabled(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._edge(bot=MagicMock(), update=update)
telegram._edge(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert "Edge is not enabled." in msg_mock.call_args_list[0][0][0]
@ -1137,7 +1164,7 @@ def test_edge_enabled(edge_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._edge(bot=MagicMock(), update=update)
telegram._edge(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '<b>Edge only validated following pairs:</b>\n<pre>' in msg_mock.call_args_list[0][0][0]
assert 'Pair Winrate Expectancy Stoploss' in msg_mock.call_args_list[0][0][0]
@ -1154,7 +1181,7 @@ def test_help_handle(default_conf, update, mocker) -> None:
telegram = Telegram(freqtradebot)
telegram._help(bot=MagicMock(), update=update)
telegram._help(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*/help:* `This help message`' in msg_mock.call_args_list[0][0][0]
@ -1169,7 +1196,7 @@ def test_version_handle(default_conf, update, mocker) -> None:
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._version(bot=MagicMock(), update=update)
telegram._version(update=update, context=MagicMock())
assert msg_mock.call_count == 1
assert '*Version:* `{}`'.format(__version__) in msg_mock.call_args_list[0][0][0]
@ -1395,9 +1422,11 @@ def test__send_msg(default_conf, mocker) -> None:
bot = MagicMock()
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._updater = MagicMock()
telegram._updater.bot = bot
telegram._config['telegram']['enabled'] = True
telegram._send_msg('test', bot)
telegram._send_msg('test')
assert len(bot.method_calls) == 1
@ -1407,9 +1436,11 @@ def test__send_msg_network_error(default_conf, mocker, caplog) -> None:
bot.send_message = MagicMock(side_effect=NetworkError('Oh snap'))
freqtradebot = get_patched_freqtradebot(mocker, default_conf)
telegram = Telegram(freqtradebot)
telegram._updater = MagicMock()
telegram._updater.bot = bot
telegram._config['telegram']['enabled'] = True
telegram._send_msg('test', bot)
telegram._send_msg('test')
# Bot should've tried to send it twice
assert len(bot.method_calls) == 2

View File

@ -2,7 +2,7 @@
# mainly used for Raspberry pi installs
ccxt==1.18.1115
SQLAlchemy==1.3.8
python-telegram-bot==11.1.0
python-telegram-bot==12.0.0
arrow==0.14.6
cachetools==3.1.1
requests==2.22.0