Skip to content

Commit

Permalink
Add basic support for modules and cogs.
Browse files Browse the repository at this point in the history
  • Loading branch information
EvieePy committed Jan 21, 2020
1 parent a0e8a97 commit 93fb76b
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 7 deletions.
1 change: 1 addition & 0 deletions twitchio/ext/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .core import *
from .errors import *
from .cooldowns import *
from .meta import Cog
34 changes: 32 additions & 2 deletions twitchio/ext/commands/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"""

import asyncio
import importlib
import inspect
import itertools
import sys
Expand All @@ -33,6 +34,7 @@
from twitchio.websocket import WSConnection
from .core import *
from .errors import *
from .meta import Cog
from .stringparser import StringParser
from .utils import _CaseInsensitiveDict

Expand All @@ -57,9 +59,9 @@ def __init__(self, irc_token: str, *, nick: str, prefix: Union[str, list, tuple]
self._commands = {}
self._command_aliases = {}

self._events = {}
self._modules = {}
self._cogs = {}

self._events = {}
self._checks = []

self.__init__commands__()
Expand Down Expand Up @@ -250,6 +252,34 @@ async def handle_checks(self, context):
except Exception as e:
return e

def load_module(self, name: str):
"""Method which loads a module and it's cogs.
Parameters
------------
name: str
The name of the module to load in dot.path format.
"""
if name in self._modules:
return

module = importlib.import_module(name)

if hasattr(module, 'prepare'):
module.prepare(self)
else:
del module
del sys.modules[name]
raise ImportError(f'Module <{name}> is missing a prepare method')

if name not in self._modules:
self._modules[name] = module

def add_cog(self, cog):
if not isinstance(cog, Cog):
raise InvalidCog('Cogs must derive from "commands.Cog".')

cog._load_methods(self)

async def global_before_invoke(self, ctx):
"""|coro|
Expand Down
9 changes: 6 additions & 3 deletions twitchio/ext/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def __init__(self, name: str, func, **attrs):
self._cooldowns = []
self._name = name

self._instance = None
self.cog = None

try:
self._checks.extend(func.__checks__)
except AttributeError:
Expand All @@ -66,8 +69,6 @@ def __init__(self, name: str, func, **attrs):
self._after_invoke = None
self.no_global_checks = attrs.get('no_global_checks', False)

self._instance = None

for key, value in self.params.items():
if isinstance(value.annotation, str):
self.params[key] = value.replace(annotation=eval(value.annotation, func.__globals__))
Expand Down Expand Up @@ -156,7 +157,9 @@ def __init__(self, message, **attrs):
self.prefix = attrs.get('prefix')

self.command = attrs.get('command')
self.cog = attrs.get('cog')
if self.command:
self.cog = self.command.cog

self.args = attrs.get('args')
self.kwargs = attrs.get('kwargs')

Expand Down
4 changes: 4 additions & 0 deletions twitchio/ext/commands/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class InvalidCogMethod(TwitchCommandError):
pass


class InvalidCog(TwitchCommandError):
pass


class MissingRequiredArgument(TwitchCommandError):
pass

Expand Down
40 changes: 38 additions & 2 deletions twitchio/ext/commands/meta.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
The MIT License (MIT)
Copyright (c) 2017-2019 TwitchIO
Copyright (c) 2017-2020 TwitchIO
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand All @@ -20,4 +20,40 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
"""

import inspect
from .core import *
from .errors import *


class Cog:

__valid_slots__ = ('cog_unload', 'cog_check', 'cog_error', )

def __init_subclass__(cls, *args, **kwargs):

try:
cls.__name__ = cls.name
except AttributeError:
cls.name = cls.__name__

for name, mem in inspect.getmembers(cls):
if name.startswith(('cog', 'bot')) and name not in cls.__valid_slots__: # Invalid method prefixes
raise InvalidCogMethod(f'The method "{name}" starts with an invalid prefix (cog or bot).')

cls._events = {}
cls._commands = {}

def _load_methods(self, bot):
for name, method in inspect.getmembers(self):
if isinstance(method, Command):
method._instance = self
method.cog = self

self._commands[name] = method
bot.add_command(method)

@property
def commands(self):
return self._commands

0 comments on commit 93fb76b

Please sign in to comment.