Skip to content

Commit fc38629

Browse files
author
Pietro Albini
committed
Merge branch 'master' into release-next
2 parents fc0073e + bfc4cb2 commit fc38629

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1509
-633
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pip, virtualenv, setuptools and [invoke][3] installed:
4747
$ cd botogram
4848
$ invoke install
4949

50-
On some Linux systems you might need to wrap the ``make install`` command with
50+
On some Linux systems you might need to wrap the ``invoke install`` command with
5151
``sudo``, if you don't have root privileges.
5252

5353
[1]: https://core.telegram.org/bots

botogram/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(self, api_key, endpoint=None):
3636

3737
def call(self, method, params=None, files=None, expect=None):
3838
"""Call a method of the API"""
39-
url = self._endpoint+"bot%s/%s" % (self._api_key, method)
39+
url = self._endpoint + "bot%s/%s" % (self._api_key, method)
4040
response = requests.get(url, params=params, files=files)
4141
content = response.json()
4242

@@ -55,7 +55,7 @@ def call(self, method, params=None, files=None, expect=None):
5555

5656
def file_content(self, path):
5757
"""Get the content of an user-submitted file"""
58-
url = self._endpoint+"file/bot%s/%s" % (self._api_key, path)
58+
url = self._endpoint + "file/bot%s/%s" % (self._api_key, path)
5959
response = requests.get(url)
6060

6161
return response.content

botogram/bot.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ def __init__(self, api_connection):
5454
self._shared_memory = shared.SharedMemory()
5555

5656
# Register bot's shared memory initializers
57-
inits = self._main_component._get_shared_memory_inits()
57+
inits = self._main_component._get_chains()["memory_preparers"][0]
5858
maincompid = self._main_component._component_id
59-
self._shared_memory.register_inits_list(maincompid, inits)
59+
self._shared_memory.register_preparers_list(maincompid, inits)
6060

6161
# Setup the scheduler
6262
self._scheduler = tasks.Scheduler()
@@ -83,7 +83,7 @@ def __init__(self, api_connection):
8383

8484
# This regex will match all commands pointed to this bot
8585
self._commands_re = re.compile(r'^\/([a-zA-Z0-9_]+)(@' +
86-
self.itself.username+r')?( .*)?$')
86+
self.itself.username + r')?( .*)?$')
8787

8888
def __reduce__(self):
8989
# Use the standard __reduce__
@@ -142,11 +142,17 @@ def __(func):
142142
return func
143143
return __
144144

145-
def init_shared_memory(self, func):
146-
"""Register a shared memory's initializer"""
147-
self._main_component.add_shared_memory_initializer(func)
145+
def prepare_memory(self, func):
146+
"""Register a shared memory's preparer"""
147+
self._main_component.add_memory_preparer(func)
148148
return func
149149

150+
@utils.deprecated("@bot.init_shared_memory", "1.0", "Rename the decorator "
151+
"to @bot.prepare_memory")
152+
def init_shared_memory(self, func):
153+
"""This decorator is deprecated, and it calls @prepare_memory"""
154+
return self.prepare_memory(func)
155+
150156
def use(self, *components, only_init=False):
151157
"""Use the provided components in the bot"""
152158
for component in components:
@@ -156,12 +162,13 @@ def use(self, *components, only_init=False):
156162
self._components.append(component)
157163

158164
# Register initializers for the shared memory
165+
chains = component._get_chains()
159166
compid = component._component_id
160-
inits = component._get_shared_memory_inits()
161-
self._shared_memory.register_inits_list(compid, inits)
167+
preparers = chains["memory_preparers"][0]
168+
self._shared_memory.register_preparers_list(compid, preparers)
162169

163170
# Register tasks
164-
self._scheduler.register_tasks_list(component._get_timers())
171+
self._scheduler.register_tasks_list(chains["tasks"][0])
165172

166173
def process(self, update):
167174
"""Process an update object"""
@@ -178,12 +185,20 @@ def run(self, workers=2):
178185

179186
def freeze(self):
180187
"""Return a frozen instance of the bot"""
188+
chains = components.merge_chains(self._main_component,
189+
*self._components)
190+
191+
# Get the list of commands for the bot
192+
commands = self._components[-1]._get_commands()
193+
for component in reversed(self._components[:-1]):
194+
commands.update(component._get_commands())
195+
commands.update(self._main_component._get_commands())
196+
181197
return frozenbot.FrozenBot(self.api, self.about, self.owner,
182198
self.hide_commands, self.before_help,
183199
self.after_help, self.process_backlog,
184200
self.lang, self.itself, self._commands_re,
185-
self._components+[self._main_component],
186-
self._scheduler,
201+
commands, chains, self._scheduler,
187202
self._main_component._component_id,
188203
self._bot_id, self._shared_memory)
189204

botogram/components.py

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __new__(cls, *args, **kwargs):
2727
self.__processors = []
2828
self.__no_commands = []
2929
self.__before_processors = []
30-
self.__shared_inits = []
30+
self.__memory_preparers = []
3131
self.__timers = []
3232

3333
self._component_id = str(uuid.uuid4())
@@ -122,13 +122,19 @@ def add_timer(self, interval, func):
122122

123123
self.__timers.append(job)
124124

125-
def add_shared_memory_initializer(self, func):
125+
def add_memory_preparer(self, func):
126126
"""Add a new shared memory's initializer"""
127127
if not callable(func):
128-
raise ValueError("A shared memory initializer must be callable")
128+
raise ValueError("A memory preparer must be callable")
129+
130+
hook = hooks.MemoryPreparerHook(func, self)
131+
self.__memory_preparers.append(hook)
129132

130-
hook = hooks.SharedMemoryInitializerHook(func, self)
131-
self.__shared_inits.append(hook)
133+
@utils.deprecated("Component.add_shared_memory_initializer", "1.0",
134+
"Rename the method to Component.add_memory_preparer")
135+
def add_shared_memory_initializer(self, func):
136+
"""This method is deprecated, and it calls add_memory_preparer"""
137+
self.add_memory_preparer(func)
132138

133139
def _add_no_commands_hook(self, func):
134140
"""Register an hook which will be executed when no commands matches"""
@@ -138,23 +144,49 @@ def _add_no_commands_hook(self, func):
138144
hook = hooks.NoCommandsHook(func, self)
139145
self.__no_commands.append(hook)
140146

141-
def _get_hooks_chain(self):
147+
def _get_chains(self):
142148
"""Get the full hooks chain for this component"""
143-
return [
149+
messages = [
144150
self.__before_processors[:],
145151
[self.__commands[name] for name in sorted(self.__commands.keys())],
146152
self.__no_commands[:],
147153
self.__processors[:],
148154
]
155+
return {
156+
"messages": messages,
157+
"memory_preparers": [self.__memory_preparers],
158+
"tasks": [self.__timers],
159+
}
149160

150161
def _get_commands(self):
151162
"""Get all the commands this component implements"""
152163
return self.__commands
153164

154-
def _get_shared_memory_inits(self):
155-
"""Get a list of all the shared memory initializers"""
156-
return self.__shared_inits
157165

158-
def _get_timers(self):
159-
"""Get a list of all the timers"""
160-
return self.__timers
166+
def merge_chains(main, *components):
167+
"""Merge multiple chains returned by the components"""
168+
merged = {}
169+
components = [main] + list(reversed(components))
170+
171+
# First of all, merge all the subchains of the different components
172+
# together -- This is a separate step so the order is preserved
173+
for component in components:
174+
macrochains = component._get_chains()
175+
for kind, chains in macrochains.items():
176+
if kind not in merged:
177+
merged[kind] = []
178+
179+
for i, chain in enumerate(chains):
180+
try:
181+
merged[kind][i] += chain
182+
except IndexError:
183+
merged[kind].append(chain[:])
184+
185+
# Then merge all the subchains together
186+
result = {}
187+
for kind, chains in merged.items():
188+
result[kind] = []
189+
for chain in chains:
190+
result[kind] += chain
191+
192+
return result

botogram/defaults.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def start_command(self, bot, chat):
2828
message = []
2929
if bot.about:
3030
message.append(bot.about)
31+
message.append("")
3132
message.append(bot._("Use /help to get a list of all the commands."))
3233

3334
chat.send("\n".join(message))
@@ -44,14 +45,15 @@ def _start_command_help(bot):
4445
def help_command(self, bot, chat, args):
4546
commands = bot._get_commands()
4647
if len(args) > 1:
47-
message = [bot._("Error: the /help command allows up to one "
48+
message = [bot._("*Error!* The `/help` command allows up to one "
4849
"argument.")]
4950
elif len(args) == 1:
5051
if args[0] in commands:
5152
message = self._help_command_message(bot, commands, args[0])
5253
else:
53-
message = [bot._("Unknown command: /%(name)s.", name=args[0]),
54-
bot._("Use /help for a list of commands.")]
54+
message = [bot._("*Unknown command:* `/%(name)s`",
55+
name=args[0]),
56+
bot._("Use /help to get a list of the commands.")]
5557
else:
5658
message = self._help_generic_message(bot, commands)
5759

@@ -72,19 +74,21 @@ def _help_generic_message(self, bot, commands):
7274

7375
# Show help on commands
7476
if len(commands) > 0:
75-
message.append(bot._("Available commands:"))
77+
message.append(bot._("*This bot supports those commands:*"))
7678
for name in sorted(commands.keys()):
7779
# Allow to hide commands in the help message
7880
if name in bot.hide_commands:
7981
continue
8082

8183
func = commands[name]
82-
docstring = utils.docstring_of(func, bot).split("\n", 1)[0]
83-
message.append("/%s - %s" % (name, docstring))
84-
message.append(bot._("You can also use '/help <command>' to get "
84+
docstring = utils.docstring_of(func, bot, format=True) \
85+
.split("\n", 1)[0]
86+
message.append("/%s `-` %s" % (name, docstring))
87+
message.append("")
88+
message.append(bot._("You can also use `/help <command>` to get "
8589
"help about a specific command."))
8690
else:
87-
message.append(bot._("No commands available."))
91+
message.append(bot._("_This bot has no commands._"))
8892

8993
if len(bot.after_help):
9094
message.append("")
@@ -104,8 +108,8 @@ def _help_command_message(self, bot, commands, command):
104108
message = []
105109

106110
func = commands[command]
107-
docstring = utils.docstring_of(func, bot)
108-
message.append("/%s - %s" % (command, docstring))
111+
docstring = utils.docstring_of(func, bot, format=True)
112+
message.append("/%s `-` %s" % (command, docstring))
109113

110114
# Show the owner informations
111115
if bot.owner:
@@ -121,7 +125,7 @@ def _help_command_help(bot):
121125
"""Get the help message of this command"""
122126
return "\n".join([
123127
bot._("Show this help message."),
124-
bot._("You can also use '/help <command>' to get help about a "
128+
bot._("You can also use `/help <command>` to get help about a "
125129
"specific command."),
126130
])
127131

@@ -144,7 +148,7 @@ def no_commands_hook(self, bot, chat, message):
144148
single_user = chat.type == "private"
145149
if mentioned or single_user:
146150
chat.send("\n".join([
147-
bot._("Unknown command: /%(name)s", name=command),
148-
bot._("Use /help for a list of commands"),
151+
bot._("*Unknown command:* `/%(name)s`", name=command),
152+
bot._("Use /help to get a list of the commands."),
149153
]))
150154
return True

0 commit comments

Comments
 (0)