Skip to content

Commit b981ea9

Browse files
committed
Added prefix='/' : str argument to CommandHandler
1 parent b275031 commit b981ea9

File tree

2 files changed

+141
-85
lines changed

2 files changed

+141
-85
lines changed

telegram/ext/commandhandler.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
from future.utils import string_types
2323

24-
from .handler import Handler
2524
from telegram import Update
25+
from .handler import Handler
2626

2727

2828
class CommandHandler(Handler):
@@ -39,6 +39,8 @@ class CommandHandler(Handler):
3939
Filters.
4040
allow_edited (:obj:`bool`): Optional. Determines Whether the handler should also accept
4141
edited messages.
42+
prefix (:obj:`bool`): Optional. Denotes the leading character of commands with this
43+
handler.
4244
pass_args (:obj:`bool`): Optional. Determines whether the handler should be passed
4345
``args``.
4446
pass_update_queue (:obj:`bool`): Optional. Determines whether ``update_queue`` will be
@@ -68,6 +70,8 @@ class CommandHandler(Handler):
6870
operators (& for and, | for or, ~ for not).
6971
allow_edited (:obj:`bool`, optional): Determines whether the handler should also accept
7072
edited messages. Default is ``False``.
73+
prefix (:obj:`str`, optional): Denotes the leading character to commands with this handler.
74+
Must be exactly one character or an empty string. Default is ``/``.
7175
pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the
7276
arguments passed to the command as a keyword argument called ``args``. It will contain
7377
a list of strings, which is the text following the command split on single or
@@ -92,6 +96,7 @@ def __init__(self,
9296
callback,
9397
filters=None,
9498
allow_edited=False,
99+
prefix='/',
95100
pass_args=False,
96101
pass_update_queue=False,
97102
pass_job_queue=False,
@@ -110,6 +115,15 @@ def __init__(self,
110115
self.command = [x.lower() for x in command]
111116
self.filters = filters
112117
self.allow_edited = allow_edited
118+
if prefix is None or not isinstance(prefix, string_types) or len(prefix) > 1:
119+
raise ValueError("The prefix argument to CommandHandler must be a single character or "
120+
"an empty string.")
121+
if prefix == ' ':
122+
# A leading space character is stripped away in Telegram messages, so we can consider
123+
# it as an empty string prefix.
124+
self.prefix = ''
125+
else:
126+
self.prefix = prefix
113127
self.pass_args = pass_args
114128

115129
# We put this up here instead of with the rest of checking code
@@ -133,10 +147,16 @@ def check_update(self, update):
133147
and (update.message or update.edited_message and self.allow_edited)):
134148
message = update.message or update.edited_message
135149

136-
if message.text and message.text.startswith('/') and len(message.text) > 1:
137-
command = message.text[1:].split(None, 1)[0].split('@')
138-
command.append(
139-
message.bot.username) # in case the command was send without a username
150+
empty_leader = self.prefix == ''
151+
command_text_nonempty = message.text and len(message.text) > 1
152+
is_valid_command = command_text_nonempty and (empty_leader or
153+
message.text.startswith(self.prefix))
154+
if is_valid_command:
155+
leader_stripped = message.text if empty_leader else message.text[1:]
156+
command = leader_stripped.split(None, 1)[0].split('@')
157+
158+
# Append the bot's username in any case
159+
command.append(message.bot.username)
140160

141161
if self.filters is None:
142162
res = True

tests/test_commandhandler.py

Lines changed: 116 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ def message(bot):
5151
return Message(1, None, None, None, bot=bot)
5252

5353

54+
@pytest.fixture(scope='function')
55+
def prefixes():
56+
return ['/', '#', '', ' ']
57+
58+
5459
class TestCommandHandler(object):
5560
test_flag = False
5661

@@ -75,62 +80,72 @@ def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
7580
def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
7681
self.test_flag = (job_queue is not None) and (update_queue is not None)
7782

78-
def ch_callback_args(self, bot, update, args):
79-
if update.message.text == '/test':
83+
def ch_callback_args(self, bot, update, args, prefix):
84+
if update.message.text == '{}test'.format(prefix):
8085
self.test_flag = len(args) == 0
81-
elif update.message.text == '/test@{}'.format(bot.username):
86+
elif update.message.text == '{}test@{}'.format(prefix, bot.username):
8287
self.test_flag = len(args) == 0
8388
else:
8489
self.test_flag = args == ['one', 'two']
8590

86-
def test_basic(self, dp, message):
87-
handler = CommandHandler('test', self.callback_basic)
88-
dp.add_handler(handler)
91+
def test_basic(self, dp, message, prefixes):
92+
for p in prefixes:
93+
handler = CommandHandler('test', self.callback_basic, prefix=p)
94+
dp.add_handler(handler)
8995

90-
message.text = '/test'
91-
assert handler.check_update(Update(0, message))
92-
dp.process_update(Update(0, message))
93-
assert self.test_flag
96+
message.text = '{}test'.format(p)
97+
assert handler.check_update(Update(0, message))
98+
dp.process_update(Update(0, message))
99+
assert self.test_flag
94100

95-
message.text = '/nottest'
96-
assert not handler.check_update(Update(0, message))
101+
message.text = '{}nottest'.format(p)
102+
assert not handler.check_update(Update(0, message))
97103

98-
message.text = 'test'
99-
assert not handler.check_update(Update(0, message))
104+
message.text = 'test'
105+
result = handler.check_update(Update(0, message))
106+
if p in ['', ' ']:
107+
assert result
108+
else:
109+
assert not result
100110

101-
message.text = 'not /test at start'
102-
assert not handler.check_update(Update(0, message))
111+
message.text = 'not {}test at start'.format(p)
112+
assert not handler.check_update(Update(0, message))
103113

104-
def test_command_list(self, message):
105-
handler = CommandHandler(['test', 'start'], self.callback_basic)
114+
dp.remove_handler(handler)
106115

107-
message.text = '/test'
108-
assert handler.check_update(Update(0, message))
116+
def test_command_list(self, message, prefixes):
117+
for p in prefixes:
118+
handler = CommandHandler(['test', 'start'], self.callback_basic, prefix=p)
109119

110-
message.text = '/start'
111-
assert handler.check_update(Update(0, message))
120+
message.text = '{}test'.format(p)
121+
assert handler.check_update(Update(0, message))
112122

113-
message.text = '/stop'
114-
assert not handler.check_update(Update(0, message))
123+
message.text = '{}start'.format(p)
124+
assert handler.check_update(Update(0, message))
115125

116-
def test_edited(self, message):
117-
handler = CommandHandler('test', self.callback_basic, allow_edited=False)
126+
message.text = '{}stop'.format(p)
127+
assert not handler.check_update(Update(0, message))
118128

119-
message.text = '/test'
120-
assert handler.check_update(Update(0, message))
121-
assert not handler.check_update(Update(0, edited_message=message))
122-
handler.allow_edited = True
123-
assert handler.check_update(Update(0, message))
124-
assert handler.check_update(Update(0, edited_message=message))
129+
def test_edited(self, message, prefixes):
130+
for p in prefixes:
131+
handler = CommandHandler('test', self.callback_basic, allow_edited=False, prefix=p)
125132

126-
def test_directed_commands(self, message):
127-
handler = CommandHandler('test', self.callback_basic)
133+
message.text = '{}test'.format(p)
134+
assert handler.check_update(Update(0, message))
135+
assert not handler.check_update(Update(0, edited_message=message))
136+
handler.allow_edited = True
137+
assert handler.check_update(Update(0, message))
138+
assert handler.check_update(Update(0, edited_message=message))
128139

129-
message.text = '/test@{}'.format(message.bot.username)
130-
assert handler.check_update(Update(0, message))
140+
def test_directed_commands(self, message, prefixes):
141+
for p in prefixes:
142+
handler = CommandHandler('test', self.callback_basic, prefix=p)
131143

132-
message.text = '/test@otherbot'
133-
assert not handler.check_update(Update(0, message))
144+
message.text = '{}test@{}'.format(p, message.bot.username)
145+
assert handler.check_update(Update(0, message))
146+
147+
message.text = '{}test@otherbot'.format(p)
148+
assert not handler.check_update(Update(0, message))
134149

135150
def test_with_filter(self, message):
136151
handler = CommandHandler('test', self.callback_basic, Filters.group)
@@ -142,53 +157,74 @@ def test_with_filter(self, message):
142157
message.chat = Chat(23, 'private')
143158
assert not handler.check_update(Update(0, message))
144159

145-
def test_pass_args(self, dp, message):
146-
handler = CommandHandler('test', self.ch_callback_args, pass_args=True)
147-
dp.add_handler(handler)
148-
149-
message.text = '/test'
150-
dp.process_update(Update(0, message=message))
151-
assert self.test_flag
152-
153-
self.test_flag = False
154-
message.text = '/test@{}'.format(message.bot.username)
155-
dp.process_update(Update(0, message=message))
156-
assert self.test_flag
157-
158-
self.test_flag = False
159-
message.text = '/test one two'
160-
dp.process_update(Update(0, message=message))
161-
assert self.test_flag
162-
163-
self.test_flag = False
164-
message.text = '/test@{} one two'.format(message.bot.username)
165-
dp.process_update(Update(0, message=message))
166-
assert self.test_flag
167-
168-
def test_newline(self, dp, message):
169-
handler = CommandHandler('test', self.callback_basic)
170-
dp.add_handler(handler)
160+
def test_pass_args(self, dp, message, prefixes):
161+
for p in prefixes:
162+
handler = CommandHandler(
163+
'test',
164+
lambda bot, update, args: self.ch_callback_args(bot, update, args, p),
165+
pass_args=True,
166+
prefix=p
167+
)
168+
dp.add_handler(handler)
169+
170+
self.test_flag = False
171+
message.text = '{}test'.format(p)
172+
dp.process_update(Update(0, message=message))
173+
assert self.test_flag
174+
175+
self.test_flag = False
176+
message.text = '{}test@{}'.format(p, message.bot.username)
177+
dp.process_update(Update(0, message=message))
178+
assert self.test_flag
179+
180+
self.test_flag = False
181+
message.text = '{}test one two'.format(p)
182+
dp.process_update(Update(0, message=message))
183+
assert self.test_flag
184+
185+
self.test_flag = False
186+
message.text = '{}test@{} one two'.format(p, message.bot.username)
187+
dp.process_update(Update(0, message=message))
188+
assert self.test_flag
189+
190+
dp.remove_handler(handler)
191+
192+
def test_newline(self, dp, message, prefixes):
193+
for p in prefixes:
194+
handler = CommandHandler('test', self.callback_basic, prefix=p)
195+
dp.add_handler(handler)
196+
197+
message.text = '{}test\nfoobar'.format(p)
198+
assert handler.check_update(Update(0, message))
199+
dp.process_update(Update(0, message))
200+
assert self.test_flag
201+
202+
dp.remove_handler(handler)
203+
204+
def test_single_char(self, message):
205+
# Regression test for
206+
# https://github.com/python-telegram-bot/python-telegram-bot/issues/871
171207

172-
message.text = '/test\nfoobar'
173-
assert handler.check_update(Update(0, message))
174-
dp.process_update(Update(0, message))
175-
assert self.test_flag
208+
message.text = 'a'
176209

177-
def test_single_char(self, dp, message):
178-
# Regression test for https://github.com/python-telegram-bot/python-telegram-bot/issues/871
179-
handler = CommandHandler('test', self.callback_basic)
180-
dp.add_handler(handler)
210+
normal_handler = CommandHandler('test', self.callback_basic)
211+
assert not normal_handler.check_update(Update(0, message))
181212

182-
message.text = 'a'
183-
assert not handler.check_update(Update(0, message))
213+
empty_prefix_handler = CommandHandler('test', self.callback_basic, prefix='')
214+
assert not empty_prefix_handler.check_update(Update(0, message))
184215

185-
def test_single_slash(self, dp, message):
186-
# Regression test for https://github.com/python-telegram-bot/python-telegram-bot/issues/871
187-
handler = CommandHandler('test', self.callback_basic)
188-
dp.add_handler(handler)
216+
def test_single_prefix(self, dp, message, prefixes):
217+
for p in prefixes:
218+
# Regression test for
219+
# https://github.com/python-telegram-bot/python-telegram-bot/issues/871
220+
handler = CommandHandler('test', self.callback_basic, prefix=p)
221+
dp.add_handler(handler)
189222

190-
message.text = '/'
191-
assert not handler.check_update(Update(0, message))
223+
# Note: In praxis, it is not possible to send empty messages.
224+
# We will test this case nonetheless
225+
message.text = p
226+
assert not handler.check_update(Update(0, message))
227+
dp.remove_handler(handler)
192228

193229
def test_pass_user_or_chat_data(self, dp, message):
194230
handler = CommandHandler('test', self.callback_data_1, pass_user_data=True)

0 commit comments

Comments
 (0)