Migrate core to Python 3.5.
authorCMDR furrycat <elite@furrycat.net>
Thu, 2 Mar 2017 10:14:44 +0000 (10:14 +0000)
committerCMDR furrycat <elite@furrycat.net>
Thu, 2 Mar 2017 10:14:44 +0000 (10:14 +0000)
app.py
bot.py
cat.py

diff --git a/app.py b/app.py
index 4b302ff..2ad9762 100644 (file)
--- 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 (file)
--- 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 (file)
--- 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)