2626from functools import partial
2727
2828from .core import *
29- from .errors import *
3029
3130
3231__all__ = ("Cog" ,)
3332
3433
35- class Cog :
34+ class CogEvent :
35+ def __init__ (self , * , name : str , func ):
36+ self .name = name
37+ self .func = func
38+
39+
40+ class CogMeta (type ):
41+ def __new__ (mcs , * args , ** kwargs ):
42+ name , bases , attrs = args
43+ attrs ["__cogname__" ] = kwargs .pop ("name" , name )
44+
45+ self = super ().__new__ (mcs , name , bases , attrs , ** kwargs )
46+ self ._events = {}
47+ self ._commands = {}
48+
49+ for name , mem in inspect .getmembers (self ):
50+ if isinstance (mem , (CogEvent , Command )):
51+ if name .startswith (("cog_" , "bot_" )): # Invalid method prefixes
52+ raise RuntimeError (f'The event or command "{ name } " starts with an invalid prefix (cog_ or bot_).' )
53+
54+ if isinstance (mem , CogEvent ):
55+ try :
56+ self ._events [mem .name ].append (mem .func )
57+ except KeyError :
58+ self ._events [mem .name ] = [mem .func ]
59+
60+ return self
61+
62+
63+ class Cog (metaclass = CogMeta ):
3664 """Class used for creating a TwitchIO Cog.
3765
3866 Cogs help organise code and provide powerful features for creating bots.
@@ -74,18 +102,6 @@ def prepare(bot: commands.Bot):
74102 bot.add_cog(MyCog(bot))
75103 """
76104
77- __valid_slots__ = ("cog_unload" , "cog_check" , "cog_error" , "cog_command_error" )
78-
79- def __init_subclass__ (cls , * args , ** kwargs ):
80- cls .__cogname__ = kwargs .get ("name" , cls .__name__ )
81-
82- for name , mem in inspect .getmembers (cls ):
83- if name .startswith (("cog" , "bot" )) and name not in cls .__valid_slots__ : # Invalid method prefixes
84- raise InvalidCogMethod (f'The method "{ name } " starts with an invalid prefix (cog or bot).' )
85-
86- cls ._events = getattr (cls , "_events" , {})
87- cls ._commands = {}
88-
89105 def _load_methods (self , bot ):
90106 for name , method in inspect .getmembers (self ):
91107 if isinstance (method , Command ):
@@ -102,12 +118,6 @@ def _load_methods(self, bot):
102118 for callback in callbacks :
103119
104120 callback = partial (callback , self )
105-
106- if event in self ._events :
107- self ._events [event ].append (callback )
108- else :
109- self ._events [event ] = [callback ]
110-
111121 bot .add_event (callback = callback , name = event )
112122
113123 def _unload_methods (self , bot ):
@@ -147,20 +157,11 @@ async def event_message(self, message: twitchio.Message):
147157 async def bot_is_ready(self):
148158 print('Bot is ready!')
149159 """
150- if not hasattr (cls , "_events" ):
151- cls ._events = {}
152160
153161 def decorator (func ):
154162 event_name = event or func .__name__
155- if event_name in cls .__valid_slots__ :
156- raise ValueError (f"{ event_name } cannot be a decorated event." )
157-
158- if event_name in cls ._events :
159- cls ._events [event_name ].append (func )
160- else :
161- cls ._events [event_name ] = [func ]
162163
163- return func
164+ return CogEvent ( name = event_name , func = func )
164165
165166 return decorator
166167
0 commit comments