Browse Source

Replace all instances of keys/values/items, command group abbreviation

pull/5/head
Andrei 9 years ago
parent
commit
d8bba96737
  1. 4
      disco/api/client.py
  2. 3
      disco/api/http.py
  3. 46
      disco/bot/bot.py
  4. 17
      disco/bot/command.py
  5. 15
      disco/bot/plugin.py
  6. 3
      disco/cli.py
  7. 3
      disco/state.py
  8. 4
      disco/types/base.py
  9. 12
      disco/types/channel.py
  10. 16
      disco/types/guild.py
  11. 2
      disco/util/websocket.py

4
disco/api/client.py

@ -1,3 +1,5 @@
import six
from disco.api.http import Routes, HTTPClient from disco.api.http import Routes, HTTPClient
from disco.util.logging import LoggingClass from disco.util.logging import LoggingClass
@ -15,7 +17,7 @@ def optional(**kwargs):
:returns: dict :returns: dict
""" """
return {k: v for k, v in kwargs.items() if v is not None} return {k: v for k, v in six.iteritems(kwargs) if v is not None}
class APIClient(LoggingClass): class APIClient(LoggingClass):

3
disco/api/http.py

@ -1,6 +1,7 @@
import requests import requests
import random import random
import gevent import gevent
import six
from holster.enum import Enum from holster.enum import Enum
@ -166,7 +167,7 @@ class HTTPClient(LoggingClass):
kwargs['headers'] = self.headers kwargs['headers'] = self.headers
# Build the bucket URL # Build the bucket URL
filtered = {k: (v if v in ('guild', 'channel') else '') for k, v in args.items()} filtered = {k: (v if v in ('guild', 'channel') else '') for k, v in six.iteritems(args)}
bucket = (route[0].value, route[1].format(**filtered)) bucket = (route[0].value, route[1].format(**filtered))
# Possibly wait if we're rate limited # Possibly wait if we're rate limited

46
disco/bot/bot.py

@ -1,7 +1,8 @@
import re import re
import os import os
import importlib import six
import inspect import inspect
import importlib
from six.moves import reload_module from six.moves import reload_module
from holster.threadlocal import ThreadLocal from holster.threadlocal import ThreadLocal
@ -48,6 +49,10 @@ class BotConfig(Config):
commands_level_getter : function commands_level_getter : function
If set, a function which when given a GuildMember or User, returns the If set, a function which when given a GuildMember or User, returns the
relevant :class:`disco.bot.commands.CommandLevels`. relevant :class:`disco.bot.commands.CommandLevels`.
commands_group_abbrev : function
If true, command groups may be abbreviated to the least common variation.
E.g. the grouping 'test' may be abbreviated down to 't', unless 'tag' exists,
in which case it may be abbreviated down to 'te'.
plugin_config_provider : Optional[function] plugin_config_provider : Optional[function]
If set, this function will replace the default configuration loading If set, this function will replace the default configuration loading
function, which normally attempts to load a file located at config/plugin_name.fmt function, which normally attempts to load a file located at config/plugin_name.fmt
@ -72,6 +77,7 @@ class BotConfig(Config):
commands_prefix = '' commands_prefix = ''
commands_allow_edit = True commands_allow_edit = True
commands_level_getter = None commands_level_getter = None
commands_group_abbrev = True
plugin_config_provider = None plugin_config_provider = None
plugin_config_format = 'yaml' plugin_config_format = 'yaml'
@ -121,6 +127,7 @@ class Bot(object):
self.client.manhole_locals['bot'] = self self.client.manhole_locals['bot'] = self
self.plugins = {} self.plugins = {}
self.group_abbrev = {}
# Only bind event listeners if we're going to parse commands # Only bind event listeners if we're going to parse commands
if self.config.commands_enabled: if self.config.commands_enabled:
@ -140,7 +147,7 @@ class Bot(object):
self.add_plugin_module(plugin_mod) self.add_plugin_module(plugin_mod)
# Convert level mapping # Convert level mapping
for k, v in self.config.levels.items(): for k, v in six.iteritems(self.config.levels):
self.config.levels[k] = CommandLevels.get(v) self.config.levels[k] = CommandLevels.get(v)
@classmethod @classmethod
@ -169,10 +176,37 @@ class Bot(object):
""" """
Generator of all commands this bots plugins have defined Generator of all commands this bots plugins have defined
""" """
for plugin in self.plugins.values(): for plugin in six.itervalues(self.plugins):
for command in plugin.commands.values(): for command in six.itervalues(plugin.commands):
yield command yield command
def recompute(self):
"""
Called when a plugin is loaded/unloaded to recompute internal state.
"""
self.compute_group_abbrev()
if self.config.commands_group_abbrev:
self.compute_command_matches_re()
def compute_group_abbrev(self):
"""
Computes all possible abbreviations for a command grouping
"""
self.group_abbrev = {}
groups = set(command.group for command in self.commands if command.group)
for group in groups:
grp = group
while grp:
# If the group already exists, means someone else thought they
# could use it so we need to
if grp in list(six.itervalues(self.group_abbrev)):
self.group_abbrev = {k: v for k, v in six.iteritems(self.group_abbrev) if v != grp}
else:
self.group_abbrev[group] = grp
grp = grp[:-1]
def compute_command_matches_re(self): def compute_command_matches_re(self):
""" """
Computes a single regex which matches all possible command combinations. Computes a single regex which matches all possible command combinations.
@ -340,7 +374,7 @@ class Bot(object):
self.plugins[cls.__name__] = cls(self, config) self.plugins[cls.__name__] = cls(self, config)
self.plugins[cls.__name__].load() self.plugins[cls.__name__].load()
self.compute_command_matches_re() self.recompute()
def rmv_plugin(self, cls): def rmv_plugin(self, cls):
""" """
@ -356,7 +390,7 @@ class Bot(object):
self.plugins[cls.__name__].unload() self.plugins[cls.__name__].unload()
del self.plugins[cls.__name__] del self.plugins[cls.__name__]
self.compute_command_matches_re() self.recompute()
def reload_plugin(self, cls): def reload_plugin(self, cls):
""" """

17
disco/bot/command.py

@ -103,12 +103,14 @@ class Command(object):
is_regex : Optional[bool] is_regex : Optional[bool]
Whether the triggers for this command should be treated as raw regex. Whether the triggers for this command should be treated as raw regex.
""" """
def __init__(self, plugin, func, trigger, args=None, level=None, def __init__(self, plugin, func, trigger, *args, **kwargs):
aliases=None, group=None, is_regex=False):
self.plugin = plugin self.plugin = plugin
self.func = func self.func = func
self.triggers = [trigger] + (aliases or []) self.triggers = [trigger]
self.update(*args, **kwargs)
def update(self, args=None, level=None, aliases=None, group=None, is_regex=None):
self.triggers += aliases or []
def resolve_role(ctx, id): def resolve_role(ctx, id):
return ctx.msg.guild.roles.get(id) return ctx.msg.guild.roles.get(id)
@ -161,7 +163,12 @@ class Command(object):
if self.is_regex: if self.is_regex:
return REGEX_FMT.format('|'.join(self.triggers)) return REGEX_FMT.format('|'.join(self.triggers))
else: else:
group = self.group + ' ' if self.group else '' group = ''
if self.group:
if self.group in self.plugin.bot.group_abbrev.get(self.group):
group = '{}(?:\w+)? '.format(self.group)
else:
group = self.group
return REGEX_FMT.format('|'.join(['^' + group + trigger for trigger in self.triggers]) + ARGS_REGEX) return REGEX_FMT.format('|'.join(['^' + group + trigger for trigger in self.triggers]) + ARGS_REGEX)
def execute(self, event): def execute(self, event):

15
disco/bot/plugin.py

@ -1,7 +1,8 @@
import inspect import six
import functools
import gevent import gevent
import inspect
import weakref import weakref
import functools
from holster.emitter import Priority from holster.emitter import Priority
@ -170,6 +171,7 @@ class Plugin(LoggingClass, PluginDeco):
if meta['type'] == 'listener': if meta['type'] == 'listener':
self.register_listener(member, meta['what'], meta['desc'], meta['priority']) self.register_listener(member, meta['what'], meta['desc'], meta['priority'])
elif meta['type'] == 'command': elif meta['type'] == 'command':
meta['kwargs']['update'] = True
self.register_command(member, *meta['args'], **meta['kwargs']) self.register_command(member, *meta['args'], **meta['kwargs'])
elif meta['type'] == 'schedule': elif meta['type'] == 'schedule':
self.register_schedule(member, *meta['args'], **meta['kwargs']) self.register_schedule(member, *meta['args'], **meta['kwargs'])
@ -260,8 +262,11 @@ class Plugin(LoggingClass, PluginDeco):
Keyword arguments to pass onto the :class:`disco.bot.command.Command` Keyword arguments to pass onto the :class:`disco.bot.command.Command`
object. object.
""" """
wrapped = functools.partial(self._dispatch, 'command', func) if kwargs.pop('update', False) and func.__name__ in self.commands:
self.commands[func.__name__] = Command(self, wrapped, *args, **kwargs) self.commands[func.__name__].update(*args, **kwargs)
else:
wrapped = functools.partial(self._dispatch, 'command', func)
self.commands[func.__name__] = Command(self, wrapped, *args, **kwargs)
def register_schedule(self, func, interval, repeat=True, init=True): def register_schedule(self, func, interval, repeat=True, init=True):
""" """
@ -303,7 +308,7 @@ class Plugin(LoggingClass, PluginDeco):
for listener in self.listeners: for listener in self.listeners:
listener.remove() listener.remove()
for schedule in self.schedules.values(): for schedule in six.itervalues(self.schedules):
schedule.kill() schedule.kill()
def reload(self): def reload(self):

3
disco/cli.py

@ -5,6 +5,7 @@ creating and running bots/clients.
from __future__ import print_function from __future__ import print_function
import os import os
import six
import logging import logging
import argparse import argparse
@ -47,7 +48,7 @@ def disco_main(run=False):
else: else:
config = ClientConfig() config = ClientConfig()
for k, v in vars(args).items(): for k, v in six.iteritems(vars(args)):
if hasattr(config, k) and v is not None: if hasattr(config, k) and v is not None:
setattr(config, k, v) setattr(config, k, v)

3
disco/state.py

@ -1,3 +1,4 @@
import six
import inflection import inflection
from collections import defaultdict, deque, namedtuple from collections import defaultdict, deque, namedtuple
@ -159,7 +160,7 @@ class State(object):
self.guilds[event.guild.id] = event.guild self.guilds[event.guild.id] = event.guild
self.channels.update(event.guild.channels) self.channels.update(event.guild.channels)
for member in event.guild.members.values(): for member in six.itervalues(event.guild.members):
self.users[member.user.id] = member.user self.users[member.user.id] = member.user
# Request full member list # Request full member list

4
disco/types/base.py

@ -178,7 +178,7 @@ class Model(six.with_metaclass(ModelMeta)):
else: else:
obj = kwargs obj = kwargs
for name, field in self._fields.items(): for name, field in six.iteritems(self._fields):
if field.src_name not in obj or not obj[field.src_name]: if field.src_name not in obj or not obj[field.src_name]:
if field.has_default(): if field.has_default():
setattr(self, field.dst_name, field.default()) setattr(self, field.dst_name, field.default())
@ -217,7 +217,7 @@ class Model(six.with_metaclass(ModelMeta)):
@classmethod @classmethod
def attach(cls, it, data): def attach(cls, it, data):
for item in it: for item in it:
for k, v in data.items(): for k, v in six.iteritems(data):
try: try:
setattr(item, k, v) setattr(item, k, v)
except: except:

12
disco/types/channel.py

@ -1,12 +1,12 @@
from holster.enum import Enum import six
from disco.types.base import Model, Field, snowflake, enum, listof, dictof, text from holster.enum import Enum
from disco.types.permissions import PermissionValue
from disco.util.snowflake import to_snowflake from disco.util.snowflake import to_snowflake
from disco.util.functional import cached_property, one_or_many, chunks from disco.util.functional import cached_property, one_or_many, chunks
from disco.types.user import User from disco.types.user import User
from disco.types.permissions import Permissions, Permissible from disco.types.base import Model, Field, snowflake, enum, listof, dictof, text
from disco.types.permissions import Permissions, Permissible, PermissionValue
from disco.voice.client import VoiceClient from disco.voice.client import VoiceClient
@ -91,7 +91,7 @@ class Channel(Model, Permissible):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Channel, self).__init__(*args, **kwargs) super(Channel, self).__init__(*args, **kwargs)
self.attach(self.overwrites.values(), {'channel_id': self.id, 'channel': self}) self.attach(six.itervalues(self.overwrites), {'channel_id': self.id, 'channel': self})
def get_permissions(self, user): def get_permissions(self, user):
""" """
@ -108,7 +108,7 @@ class Channel(Model, Permissible):
member = self.guild.members.get(user.id) member = self.guild.members.get(user.id)
base = self.guild.get_permissions(user) base = self.guild.get_permissions(user)
for ow in self.overwrites.values(): for ow in six.itervalues(self.overwrites):
if ow.id != user.id and ow.id not in member.roles: if ow.id != user.id and ow.id not in member.roles:
continue continue

16
disco/types/guild.py

@ -1,3 +1,5 @@
import six
from holster.enum import Enum from holster.enum import Enum
from disco.api.http import APIException from disco.api.http import APIException
@ -6,8 +8,8 @@ from disco.util.functional import cached_property
from disco.types.base import Model, Field, snowflake, listof, dictof, datetime, text, binary, enum from disco.types.base import Model, Field, snowflake, listof, dictof, datetime, text, binary, enum
from disco.types.user import User from disco.types.user import User
from disco.types.voice import VoiceState from disco.types.voice import VoiceState
from disco.types.permissions import PermissionValue, Permissions, Permissible
from disco.types.channel import Channel from disco.types.channel import Channel
from disco.types.permissions import PermissionValue, Permissions, Permissible
VerificationLevel = Enum( VerificationLevel = Enum(
@ -243,11 +245,11 @@ class Guild(Model, Permissible):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Guild, self).__init__(*args, **kwargs) super(Guild, self).__init__(*args, **kwargs)
self.attach(self.channels.values(), {'guild_id': self.id}) self.attach(six.itervalues(self.channels), {'guild_id': self.id})
self.attach(self.members.values(), {'guild_id': self.id}) self.attach(six.itervalues(self.members), {'guild_id': self.id})
self.attach(self.roles.values(), {'guild_id': self.id}) self.attach(six.itervalues(self.roles), {'guild_id': self.id})
self.attach(self.emojis.values(), {'guild_id': self.id}) self.attach(six.itervalues(self.emojis), {'guild_id': self.id})
self.attach(self.voice_states.values(), {'guild_id': self.id}) self.attach(six.itervalues(self.voice_states), {'guild_id': self.id})
def get_permissions(self, user): def get_permissions(self, user):
""" """
@ -281,7 +283,7 @@ class Guild(Model, Permissible):
""" """
user = to_snowflake(user) user = to_snowflake(user)
for state in self.voice_states.values(): for state in six.itervalues(self.voice_states):
if state.user_id == user: if state.user_id == user:
return state return state

2
disco/util/websocket.py

@ -24,7 +24,7 @@ class Websocket(LoggingClass, websocket.WebSocketApp):
self.emitter = Emitter(gevent.spawn) self.emitter = Emitter(gevent.spawn)
# Hack to get events to emit # Hack to get events to emit
for var in self.__dict__.keys(): for var in six.iterkeys(self.__dict__):
if not var.startswith('on_'): if not var.startswith('on_'):
continue continue

Loading…
Cancel
Save