From 25fa71dd4084d4d1d36f1f08466c085a1b21bfcb Mon Sep 17 00:00:00 2001 From: CMDR furrycat Date: Thu, 2 Mar 2017 10:14:44 +0000 Subject: [PATCH] Migrate core to Python 3.5. --- app.py | 119 +++++++++++++++++++++++++++++------------------------------------ bot.py | 78 ++++++++++++++++++------------------------ cat.py | 44 ++++++++++-------------- 3 files changed, 104 insertions(+), 137 deletions(-) diff --git a/app.py b/app.py index 4b302ff..2ad9762 100644 --- a/app.py +++ b/app.py @@ -41,22 +41,19 @@ threads_ready = multiprocessing.Value('b', False) def wait_for_prompt(p): p.expect('EDI> ') -@asyncio.coroutine -def say_expect(message, stdout): +async def say_expect(message, stdout): if stdout: log.debug(stdout) - result = yield from bot.say(message.channel, '{}```{}```'.format('{} '.format(message.author.mention) if not message.channel.is_private else '', stdout)) + result = await bot.say(message.channel, '{}```{}```'.format('{} '.format(message.author.mention) if not message.channel.is_private else '', stdout)) else: - result = yield from bot.say(message.channel, 'Sorry!') + result = await bot.say(message.channel, 'Sorry!') return result -@asyncio.coroutine -def not_admin(message): +async def not_admin(message): log.warning('Not admin: {} id {}'.format(message.author, message.author.id)) - yield from bot.maybe_say(message.channel, 'hiss!') + await bot.maybe_say(message.channel, 'hiss!') -@asyncio.coroutine -def show_help(message, *args): +async def show_help(message, *args): if len(args): command = args[0] else: @@ -91,20 +88,19 @@ def show_help(message, *args): params = modules['edi'] fn = params['fn'] args = params['args'] - yield from fn(message, 'help', 'help {}'.format(command), *args) + await fn(message, 'help', 'help {}'.format(command), *args) return else: - result = yield from plugins.handle_help(message, *args) + result = await plugins.handle_help(message, *args) if result: return lines = ['*shrugs*'] - yield from bot.say_many(message.channel, lines) + await bot.say_many(message.channel, lines) -@asyncio.coroutine -def do_commands(message, command, raw, non_admin): +async def do_commands(message, command, raw, non_admin): if not non_admin: if not bot.is_admin(message.author, message.server): - yield from not_admin(message) + await not_admin(message) return log.debug('Command: {}'.format(raw)) @@ -119,17 +115,17 @@ def do_commands(message, command, raw, non_admin): url = message.attachments[0]['url'] if url is None: log.debug('No URL for avatar') - yield from cat.zzz(message.channel) + await cat.zzz(message.channel) return - result = yield from set_avatar(url) + result = await set_avatar(url) if not result: - yield from cat.yelp(message.channel) + await cat.yelp(message.channel) return elif command == 'delete': # delete if message.channel.is_private: - yield from cat.hiss(message.channel, wake = False) + await cat.hiss(message.channel, wake = False) return args = {} @@ -138,7 +134,7 @@ def do_commands(message, command, raw, non_admin): if m is not None: if m.group(1) != 'all': limit = int(m.group(1)) - yield from client.purge_from(message.channel, *args, limit = limit) + await client.purge_from(message.channel, *args, limit = limit) return elif command == 'help': @@ -146,63 +142,60 @@ def do_commands(message, command, raw, non_admin): m = re.match(r'\bhelp\s+(.+)', raw, re.IGNORECASE) if m is not None: args = shlex.split(m.group(1)) - yield from show_help(message, *args) + await show_help(message, *args) else: - yield from show_help(message) + await show_help(message) elif command == 'idle': # idle m = re.match(r'\bidle\s+(\d+)\b', raw, re.IGNORECASE) if m is None: - yield from bot.say(message.channel, 'Sorry!') + await bot.say(message.channel, 'Sorry!') return idletime.value = int(m.group(1)) elif command == 'time': # time - yield from bot.say(message.channel, bot.iso8601(int(time.time()))) - yield from bot.maybe_play_sound(bot.voice_channel_for_user(message.author), 'purr.wav', join = False) + await bot.say(message.channel, bot.iso8601(int(time.time())), embed = embed) + await bot.maybe_play_sound(bot.voice_channel_for_user(message.author), 'purr.wav', join = False) return elif command == 'url': # Invite URL. - yield from bot.say(message.channel, "<{}>".format(discord.utils.oauth_url(client.user.id))) + await bot.say(message.channel, "<{}>".format(discord.utils.oauth_url(client.user.id))) return - yield from bot.maybe_say(message.channel, 'purr', wake = False) - yield from bot.maybe_play_sound(bot.voice_channel_for_user(message.author), 'purr.wav', join = False) + await bot.maybe_say(message.channel, 'purr', wake = False) + await bot.maybe_play_sound(bot.voice_channel_for_user(message.author), 'purr.wav', join = False) -@asyncio.coroutine -def do_edi(message, command, raw, p): +async def do_edi(message, command, raw, p): if command == 'close_to' and not '-m' in raw: raw = 'close_to' if command == 'distance': raw = raw.replace(',', '') log.info(raw) - yield from client.send_typing(message.channel) + await client.send_typing(message.channel) p.sendline(raw) wait_for_prompt(p) - yield from say_expect(message, p.before) + await say_expect(message, p.before) -@asyncio.coroutine -def do_fork(message, command, raw): - yield from client.send_typing(message.channel) +async def do_fork(message, command, raw): + await client.send_typing(message.channel) if re.search(r'[^A-Za-z0-9-_."\'\s]', raw): - yield from cat.hiss(message.channel) + await cat.hiss(message.channel) return p = pexpect.spawnu('./{}'.format(raw)) p.expect(pexpect.EOF) - yield from say_expect(message, p.before) + await say_expect(message, p.before) -@asyncio.coroutine -def maybe_sleep(): +async def maybe_sleep(): while True: if bot.status() != discord.Status.idle: now = time.time() if now - bot.get('last_spoke') >= idletime.value: - yield from bot.zzz() - yield from asyncio.sleep(60) + await bot.zzz() + await asyncio.sleep(60) p = pexpect.spawnu('./edi.py') wait_for_prompt(p) @@ -238,8 +231,7 @@ if 'admin' in plugins.plugins(): plugins.get_plugin('admin').db = db plugins.get_plugin('admin').plugins = plugins -@asyncio.coroutine -def builtin_commands(message, command, raw): +async def builtin_commands(message, command, raw): if command == 'plugins': args = shlex.split(raw) if len(args) > 1: @@ -256,43 +248,41 @@ def builtin_commands(message, command, raw): lines.append('{}: {}'.format(name, description)) else: lines.append(name) - yield from bot.say_many(message.channel, lines) + await bot.say_many(message.channel, lines) else: - yield from cat.shrug(message.channel) + await cat.shrug(message.channel) return True return False -@asyncio.coroutine -def process_module(message, command, raw): +async def process_module(message, command, raw): for module, params in modules.items(): if command in params['commands']: log.info('Recognised command "{}" from {} in "{}" module'.format(command, message.author.name, module)) fn = params['fn'] args = params['args'] - yield from fn(message, command, raw, *args) + await fn(message, command, raw, *args) return log.debug('Unrecognised command from {}!'.format(message.author.name)) if bot.status() == discord.Status.idle: - yield from cat.maybe_zzz(message.channel) + await cat.maybe_zzz(message.channel) else: - yield from cat.maybe_meow(message.channel) + await cat.maybe_meow(message.channel) return True @client.event -@asyncio.coroutine -def on_ready(): +async def on_ready(): state = db.get_state(client) if state is not None: if state['idle']: log.info('Restoring idle status.') - yield from bot.set_idle(True) + await bot.set_idle(True) if state['avatar'] != db.IDLE_AVATAR: log.info('Restoring idle avatar.') - yield from set_avatar(db.IDLE_AVATAR) + await set_avatar(db.IDLE_AVATAR) elif state['avatar'] != db.ONLINE_AVATAR: log.info('Restoring online avatar.') - yield from set_avatar(db.ONLINE_AVATAR) + await set_avatar(db.ONLINE_AVATAR) if state['last_spoke']: bot.set('last_spoke', state['last_spoke']) log.info('Logged in as {}#{}'.format(client.user.name, client.user.id)) @@ -314,8 +304,7 @@ def mentioned_in(message, explicit = True): return True @client.event -@asyncio.coroutine -def on_message(message): +async def on_message(message): if message.author.id == client.user.id: return log.debug('Got message from {}: {}'.format(message.author, message.content)) @@ -327,20 +316,18 @@ def on_message(message): if m is None: return command = m.group(1) - result = yield from builtin_commands(message, command, raw) + result = await builtin_commands(message, command, raw) if not result: - result = yield from plugins.handle_command(message, command, raw) + result = await plugins.handle_command(message, command, raw) if not result: - yield from process_module(message, command, raw) + await process_module(message, command, raw) @client.event -@asyncio.coroutine -def on_member_join(member): - yield from plugins.on_member_join(member) +async def on_member_join(member): + await plugins.on_member_join(member) @client.event -@asyncio.coroutine -def on_member_update(before, after): - yield from plugins.on_member_update(before, after) +async def on_member_update(before, after): + await plugins.on_member_update(before, after) client.run(token) diff --git a/bot.py b/bot.py index 1db2eb9..019515f 100644 --- a/bot.py +++ b/bot.py @@ -299,8 +299,7 @@ def status(): return server.me.status return None -@asyncio.coroutine -def set_avatar(url): +async def set_avatar(url): if re.match(r'^https?:', url): fd = open_url(url) else: @@ -309,7 +308,7 @@ def set_avatar(url): log.debug('Failed to open URL {} for avatar'.format(url)) return False try: - yield from client.edit_profile(avatar = fd.read()) + await client.edit_profile(avatar = fd.read()) fd.close() return True except: @@ -317,23 +316,20 @@ def set_avatar(url): log.exception("set_avatar") return False -@asyncio.coroutine -def set_idle(idle): - yield from client.change_presence(status = discord.Status.idle if idle else discord.Status.online) +async def set_idle(idle): + await client.change_presence(status = discord.Status.idle if idle else discord.Status.online) for voice in list(client.voice_clients): - yield from voice.disconnect() + await voice.disconnect() -@asyncio.coroutine -def wake_up(force = False): +async def wake_up(force = False): set('last_spoke', time.time()) if force or status() != discord.Status.online: log.info('Waking up...') - yield from set_avatar(db.ONLINE_AVATAR) - yield from set_idle(False) + await set_avatar(db.ONLINE_AVATAR) + await set_idle(False) db.set_state(client, avatar = db.ONLINE_AVATAR, idle = False, last_spoke = get('last_spoke')) -@asyncio.coroutine -def zzz(): +async def zzz(): # state = db.get_state(client) # if state is None: # change = status() != discord.Status.idle @@ -342,8 +338,8 @@ def zzz(): # if change: if status() != discord.Status.idle: log.info('Sleeping...') - yield from set_avatar(db.IDLE_AVATAR) - yield from set_idle(True) + await set_avatar(db.IDLE_AVATAR) + await set_idle(True) db.set_state(client, avatar = db.IDLE_AVATAR, idle = True) def parse_attachment(attachment, filename = None): @@ -385,29 +381,27 @@ def parse_attachment(attachment, filename = None): return parsed -@asyncio.coroutine -def maybe_say(channel, text, *, attachment = None, embed = None, probability = 0.2, wake = True): +async def maybe_say(channel, text, *, attachment = None, embed = None, probability = 0.2, wake = True): if random.random() <= probability: - yield from client.send_typing(channel) + await client.send_typing(channel) message = None if attachment is not None: parsed = parse_attachment(attachment) if parsed is not None: - message = yield from client.send_file(channel, parsed['fd'], filename = parsed['filename'], content = text) + message = await client.send_file(channel, parsed['fd'], filename = parsed['filename'], content = text) parsed['fd'].close() else: log.warning("Missing or invalid attachment!") if message is None: - message = yield from client.send_message(channel, text, embed = embed) + message = await client.send_message(channel, text, embed = embed) if wake: - yield from wake_up() + await wake_up() return message else: log.debug("Didn't bother to say {}".format(text)) return None -@asyncio.coroutine -def say(channel, text, *, attachment = None, embed = None, wake = None): +async def say(channel, text, *, attachment = None, embed = None, wake = None): args = { 'probability': 1.0 } if attachment is not None: args['attachment'] = attachment @@ -415,11 +409,10 @@ def say(channel, text, *, attachment = None, embed = None, wake = None): args['embed'] = embed if wake is not None: args['wake'] = wake - message = yield from maybe_say(channel, text, **args) + message = await maybe_say(channel, text, **args) return message -@asyncio.coroutine -def say_many(channel, lines, *, attachment = None, embed = None, maxlen = 2000): +async def say_many(channel, lines, *, attachment = None, embed = None, maxlen = 2000): while len(lines): message_len = 0 n = 0 @@ -434,7 +427,7 @@ def say_many(channel, lines, *, attachment = None, embed = None, maxlen = 2000): # We can't print too big a message. subset = lines[:n] message = '\n'.join(subset) - result = yield from say(channel, message, attachment = attachment, embed = embed) + result = await say(channel, message, attachment = attachment, embed = embed) if not result: break lines = lines[len(subset):] @@ -459,8 +452,7 @@ def voice_channel_for_user(user): if voice_channel.server in client.servers: return voice_channel -@asyncio.coroutine -def maybe_play_sound(channel, filename, *, probability = 0.05, join = True): +async def maybe_play_sound(channel, filename, *, probability = 0.05, join = True): if not channel or not filename: if join: log.warning('Missing channel and/or filename for play_sound()') @@ -471,7 +463,7 @@ def maybe_play_sound(channel, filename, *, probability = 0.05, join = True): return False while get('playing'): - yield from asyncio.sleep(1) + await asyncio.sleep(1) set('playing', True) voice = client.voice_client_in(channel.server) @@ -481,9 +473,9 @@ def maybe_play_sound(channel, filename, *, probability = 0.05, join = True): return False log.debug('Moving to voice channel {}'.format(channel)) if voice is not None: - yield from client.move_to(channel) + await client.move_to(channel) else: - yield from client.join_voice_channel(channel) + await client.join_voice_channel(channel) voice = client.voice_client_in(channel.server) if voice.channel != channel: log.error("Can't move to voice channel {}".format(channel)) @@ -494,7 +486,7 @@ def maybe_play_sound(channel, filename, *, probability = 0.05, join = True): player = voice.create_ffmpeg_player(filename) player.start() while not player.is_done(): - yield from asyncio.sleep(1) + await asyncio.sleep(1) set('playing', False) log.info('Finished playing {} in channel {}'.format(filename, channel)) except: @@ -502,9 +494,8 @@ def maybe_play_sound(channel, filename, *, probability = 0.05, join = True): set('playing', False) return False -@asyncio.coroutine -def play_sound(channel, filename, *, join = True): - result = yield from maybe_play_sound(channel, filename, probability = 1.0, join = join) +async def play_sound(channel, filename, *, join = True): + result = await maybe_play_sound(channel, filename, probability = 1.0, join = join) return result def lower_role_than(member, *, strict = False): @@ -540,17 +531,15 @@ def permission(permission_name, allow = True): overwrite.update(**args) return overwrite -@asyncio.coroutine -def overwrite_permissions(channel, whom, overwrite, *, strict = True): +async def overwrite_permissions(channel, whom, overwrite, *, strict = True): permissions = channel.overwrites_for(whom) if equal_permissions(permissions.pair(), overwrite.pair(), strict = strict): log.debug('Permissions for {} in {} are already correct.'.format(whom.name, channel.name)) return log.info('Setting permissions for {} in {} to {}'.format(whom.name, channel.name, permissions.__dict__)) - yield from client.edit_channel_permissions(channel, whom, overwrite) + await client.edit_channel_permissions(channel, whom, overwrite) -@asyncio.coroutine -def set_role(member, role, minimum = 1): +async def set_role(member, role, minimum = 1): if role is None: log.warning("Can't find {} role to assign to {}".format(role_name, member.name)) return @@ -563,7 +552,7 @@ def set_role(member, role, minimum = 1): return log.info('Adding {} role to {}'.format(role.name, member.name)) try: - yield from client.add_roles(member, role) + await client.add_roles(member, role) except discord.errors.Forbidden: log.warning('Forbidden to add {} role to {}'.format(role.name, member.name)) @@ -582,7 +571,6 @@ def ago(timestamp): def digest(text): return hashlib.sha224(text.encode('utf-8')).hexdigest() -@asyncio.coroutine -def say_exception(destination, exception): - result = yield from say_many(destination, ['```py', str(exception), '```']) +async def say_exception(destination, exception): + result = await say_many(destination, ['```py', str(exception), '```']) return result diff --git a/cat.py b/cat.py index fcbbb1f..8ff42f0 100644 --- a/cat.py +++ b/cat.py @@ -1,49 +1,41 @@ import asyncio import bot -@asyncio.coroutine -def maybe_meow(destination, voice = None, **args): +async def maybe_meow(destination, voice = None, **args): result = False if destination is not None: - result = yield from bot.maybe_say(destination, 'meow!', **args) + result = await bot.maybe_say(destination, 'meow!', **args) if result and voice is not None: - yield from bot.play_sound(voice, 'meow.wav', **args) + await bot.play_sound(voice, 'meow.wav', **args) -@asyncio.coroutine -def meow(destination, voice = None, **extra): +async def meow(destination, voice = None, **extra): args = {} args.update(**extra) args['probability'] = 1.0 - yield from maybe_meow(destination, voice, **args) + await maybe_meow(destination, voice, **args) -@asyncio.coroutine -def purr(destination, voice = None, **args): +async def purr(destination, voice = None, **args): result = False if destination is not None: - result = yield from bot.say(destination, 'purr') + result = await bot.say(destination, 'purr') if result and voice is not None: - yield from bot.play_sound(voice, 'purr.wav', **args) + await bot.play_sound(voice, 'purr.wav', **args) -@asyncio.coroutine -def hiss(destination, **args): - yield from bot.say(destination, 'hiss!', **args) +async def hiss(destination, **args): + await bot.say(destination, 'hiss!', **args) -@asyncio.coroutine -def yelp(destination, **args): - yield from bot.say(destination, 'yelp!', **args) +async def yelp(destination, **args): + await bot.say(destination, 'yelp!', **args) -@asyncio.coroutine -def shrug(destination, **args): - yield from bot.say(destination, '*shrugs*', **args) +async def shrug(destination, **args): + await bot.say(destination, '*shrugs*', **args) -@asyncio.coroutine -def maybe_zzz(destination, **args): - yield from bot.maybe_say(destination, 'zzz', **args) +async def maybe_zzz(destination, **args): + await bot.maybe_say(destination, 'zzz', **args) -@asyncio.coroutine -def zzz(destination, **extra): +async def zzz(destination, **extra): args = {} args.update(**extra) args['probability'] = 1.0 args['wake'] = False - yield from maybe_zzz(destination, **args) + await maybe_zzz(destination, **args) -- 2.7.4