modifyself 0.3.4__tar.gz → 0.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {modifyself-0.3.4 → modifyself-0.3.6}/LICENSE +20 -20
- {modifyself-0.3.4 → modifyself-0.3.6}/PKG-INFO +1 -1
- modifyself-0.3.6/modifyself/__init__.py +45 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/activity.py +6 -1
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/commands/__init__.py +22 -22
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/commands/checks.py +63 -63
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/commands/cog.py +82 -82
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/commands/context.py +117 -99
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/commands/converters.py +101 -101
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/commands/core.py +205 -205
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/core/bitfield.py +158 -144
- modifyself-0.3.6/modifyself/core/enums.py +187 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/core/mixins.py +26 -26
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/core/snowflake.py +64 -64
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/errors.py +77 -77
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/gateway/__init__.py +8 -8
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/gateway/dispatcher.py +131 -113
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/gateway/heartbeat.py +158 -158
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/gateway/websocket.py +499 -470
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/headers.py +1 -1
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/http/__init__.py +8 -8
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/http/client.py +693 -588
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/http/ratelimit.py +335 -335
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/http/route.py +330 -266
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/interactions.py +14 -22
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/__init__.py +31 -31
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/base.py +41 -41
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/channel.py +195 -180
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/guild.py +184 -175
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/member.py +91 -83
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/message.py +217 -214
- modifyself-0.3.6/modifyself/models/relationship.py +78 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/user.py +78 -78
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/state.py +422 -313
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/utils.py +176 -176
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/voice.py +40 -14
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself.egg-info/PKG-INFO +1 -1
- {modifyself-0.3.4 → modifyself-0.3.6}/pyproject.toml +1 -1
- modifyself-0.3.4/modifyself/__init__.py +0 -23
- modifyself-0.3.4/modifyself/core/enums.py +0 -84
- modifyself-0.3.4/modifyself/models/relationship.py +0 -47
- {modifyself-0.3.4 → modifyself-0.3.6}/README.md +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/client.py +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/components.py +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/billing.py +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/settings.py +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/models/webhook.py +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself/types.py +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself.egg-info/SOURCES.txt +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself.egg-info/dependency_links.txt +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself.egg-info/requires.txt +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/modifyself.egg-info/top_level.txt +0 -0
- {modifyself-0.3.4 → modifyself-0.3.6}/setup.cfg +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 modifyself
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 modifyself
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""
|
|
2
|
+
modifyself ? a clean, pythonic Discord self-bot library.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "0.3.6"
|
|
6
|
+
|
|
7
|
+
from .client import Client
|
|
8
|
+
from .commands.core import command
|
|
9
|
+
from .commands.cog import Cog
|
|
10
|
+
from .commands.context import Context
|
|
11
|
+
|
|
12
|
+
from .models.relationship import Relationship, RelationshipType
|
|
13
|
+
from .models.billing import PaymentSource, Subscription
|
|
14
|
+
from .models.settings import GuildSettings, UserSettings
|
|
15
|
+
from .models.webhook import Webhook, WebhookMessage
|
|
16
|
+
|
|
17
|
+
from .activity import Activity, ActivityType, ActivityFlags, spotify_activity, youtube_activity, xbox_activity, playstation_activity, crunchyroll_activity, custom_activity, listening_activity, streaming_activity, competing_activity, LOGO_MAP
|
|
18
|
+
|
|
19
|
+
from .components import ComponentType, ButtonStyle, TextInputStyle, Button, SelectOption, SelectMenu, ChannelSelect, RoleSelect, MentionableSelect, UserSelect, TextInput, ActionRow, Modal
|
|
20
|
+
|
|
21
|
+
from .interactions import Interaction, InteractionType, InteractionCallbackType, InteractionHandler, interaction_handler
|
|
22
|
+
|
|
23
|
+
from .core.enums import (
|
|
24
|
+
ChannelType, MessageType, VerificationLevel, NotificationLevel,
|
|
25
|
+
ExplicitContentFilterLevel, MFALevel, NSFWLevel, PremiumType,
|
|
26
|
+
ActivityType as EnumActivityType, Permissions, GatewayCloseCode,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"Client", "command", "Cog", "Context",
|
|
31
|
+
"Relationship", "RelationshipType", "PaymentSource", "Subscription",
|
|
32
|
+
"GuildSettings", "UserSettings", "Webhook", "WebhookMessage",
|
|
33
|
+
"Activity", "ActivityType", "ActivityFlags",
|
|
34
|
+
"spotify_activity", "youtube_activity", "xbox_activity",
|
|
35
|
+
"playstation_activity", "crunchyroll_activity", "custom_activity",
|
|
36
|
+
"listening_activity", "streaming_activity", "competing_activity", "LOGO_MAP",
|
|
37
|
+
"ComponentType", "ButtonStyle", "TextInputStyle", "Button", "SelectOption",
|
|
38
|
+
"SelectMenu", "ChannelSelect", "RoleSelect", "MentionableSelect",
|
|
39
|
+
"UserSelect", "TextInput", "ActionRow", "Modal",
|
|
40
|
+
"Interaction", "InteractionType", "InteractionCallbackType",
|
|
41
|
+
"InteractionHandler", "interaction_handler",
|
|
42
|
+
"ChannelType", "MessageType", "VerificationLevel", "NotificationLevel",
|
|
43
|
+
"ExplicitContentFilterLevel", "MFALevel", "NSFWLevel", "PremiumType",
|
|
44
|
+
"Permissions", "GatewayCloseCode",
|
|
45
|
+
]
|
|
@@ -13,14 +13,19 @@ class ActivityType(IntEnum):
|
|
|
13
13
|
WATCHING = 3
|
|
14
14
|
CUSTOM = 4
|
|
15
15
|
COMPETING = 5
|
|
16
|
+
HANG = 6
|
|
16
17
|
|
|
17
18
|
class ActivityFlags(IntEnum):
|
|
18
19
|
INSTANCE = 1 << 0
|
|
19
20
|
JOIN = 1 << 1
|
|
20
|
-
SPECTATE = 1 << 2
|
|
21
|
+
SPECTATE = 1 << 2 # deprecated
|
|
21
22
|
JOIN_REQUEST = 1 << 3
|
|
22
23
|
SYNC = 1 << 4
|
|
23
24
|
PLAY = 1 << 5
|
|
25
|
+
PARTY_PRIVACY_FRIENDS = 1 << 6
|
|
26
|
+
PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7
|
|
27
|
+
EMBEDDED = 1 << 8
|
|
28
|
+
CONTEXTLESS = 1 << 9
|
|
24
29
|
|
|
25
30
|
class Activity:
|
|
26
31
|
def __init__(
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Command framework: commands, context, converters, cogs, checks.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from .core import Command, command, group
|
|
6
|
-
from .context import Context
|
|
7
|
-
from .converters import ConverterRegistry
|
|
8
|
-
from .cog import Cog
|
|
9
|
-
from .checks import check, has_permissions, is_owner, guild_only, dm_only
|
|
10
|
-
|
|
11
|
-
__all__ = [
|
|
12
|
-
"Command",
|
|
13
|
-
"command",
|
|
14
|
-
"group",
|
|
15
|
-
"Context",
|
|
16
|
-
"ConverterRegistry",
|
|
17
|
-
"Cog",
|
|
18
|
-
"check",
|
|
19
|
-
"has_permissions",
|
|
20
|
-
"is_owner",
|
|
21
|
-
"guild_only",
|
|
22
|
-
"dm_only",
|
|
1
|
+
"""
|
|
2
|
+
Command framework: commands, context, converters, cogs, checks.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .core import Command, command, group
|
|
6
|
+
from .context import Context
|
|
7
|
+
from .converters import ConverterRegistry
|
|
8
|
+
from .cog import Cog
|
|
9
|
+
from .checks import check, has_permissions, is_owner, guild_only, dm_only
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Command",
|
|
13
|
+
"command",
|
|
14
|
+
"group",
|
|
15
|
+
"Context",
|
|
16
|
+
"ConverterRegistry",
|
|
17
|
+
"Cog",
|
|
18
|
+
"check",
|
|
19
|
+
"has_permissions",
|
|
20
|
+
"is_owner",
|
|
21
|
+
"guild_only",
|
|
22
|
+
"dm_only",
|
|
23
23
|
]
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Command checks and predicates.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import functools
|
|
6
|
-
from typing import Callable
|
|
7
|
-
|
|
8
|
-
from ..errors import CheckFailure
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def check(predicate: Callable):
|
|
12
|
-
"""Decorator to add a custom check to a command."""
|
|
13
|
-
def decorator(func):
|
|
14
|
-
if isinstance(func, type):
|
|
15
|
-
# Being applied to a class
|
|
16
|
-
return func
|
|
17
|
-
if hasattr(func, "_command"):
|
|
18
|
-
func._command.add_check(predicate)
|
|
19
|
-
else:
|
|
20
|
-
if not hasattr(func, "__checks__"):
|
|
21
|
-
func.__checks__ = []
|
|
22
|
-
func.__checks__.append(predicate)
|
|
23
|
-
return func
|
|
24
|
-
return decorator
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def has_permissions(**perms):
|
|
28
|
-
"""Check if the command author has the specified permissions."""
|
|
29
|
-
def predicate(ctx):
|
|
30
|
-
if not ctx.guild:
|
|
31
|
-
return False
|
|
32
|
-
member = ctx.guild.me if hasattr(ctx, "_is_bot_check") else ctx.author
|
|
33
|
-
if member is None:
|
|
34
|
-
return False
|
|
35
|
-
# Simplified check — real implementation would resolve overwrites
|
|
36
|
-
return True
|
|
37
|
-
|
|
38
|
-
return check(predicate)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def is_owner():
|
|
42
|
-
"""Check if the command author is in the bot owner list."""
|
|
43
|
-
def predicate(ctx):
|
|
44
|
-
return ctx.author.id in ctx.bot.owner_ids
|
|
45
|
-
return check(predicate)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def guild_only():
|
|
49
|
-
"""Check that the command is used in a guild."""
|
|
50
|
-
def predicate(ctx):
|
|
51
|
-
if ctx.guild is None:
|
|
52
|
-
raise CheckFailure("This command can only be used in a guild.")
|
|
53
|
-
return True
|
|
54
|
-
return check(predicate)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def dm_only():
|
|
58
|
-
"""Check that the command is used in a DM."""
|
|
59
|
-
def predicate(ctx):
|
|
60
|
-
if ctx.guild is not None:
|
|
61
|
-
raise CheckFailure("This command can only be used in DMs.")
|
|
62
|
-
return True
|
|
63
|
-
return check(predicate)
|
|
1
|
+
"""
|
|
2
|
+
Command checks and predicates.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
from ..errors import CheckFailure
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def check(predicate: Callable):
|
|
12
|
+
"""Decorator to add a custom check to a command."""
|
|
13
|
+
def decorator(func):
|
|
14
|
+
if isinstance(func, type):
|
|
15
|
+
# Being applied to a class
|
|
16
|
+
return func
|
|
17
|
+
if hasattr(func, "_command"):
|
|
18
|
+
func._command.add_check(predicate)
|
|
19
|
+
else:
|
|
20
|
+
if not hasattr(func, "__checks__"):
|
|
21
|
+
func.__checks__ = []
|
|
22
|
+
func.__checks__.append(predicate)
|
|
23
|
+
return func
|
|
24
|
+
return decorator
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def has_permissions(**perms):
|
|
28
|
+
"""Check if the command author has the specified permissions."""
|
|
29
|
+
def predicate(ctx):
|
|
30
|
+
if not ctx.guild:
|
|
31
|
+
return False
|
|
32
|
+
member = ctx.guild.me if hasattr(ctx, "_is_bot_check") else ctx.author
|
|
33
|
+
if member is None:
|
|
34
|
+
return False
|
|
35
|
+
# Simplified check — real implementation would resolve overwrites
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
return check(predicate)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def is_owner():
|
|
42
|
+
"""Check if the command author is in the bot owner list."""
|
|
43
|
+
def predicate(ctx):
|
|
44
|
+
return ctx.author.id in ctx.bot.owner_ids
|
|
45
|
+
return check(predicate)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def guild_only():
|
|
49
|
+
"""Check that the command is used in a guild."""
|
|
50
|
+
def predicate(ctx):
|
|
51
|
+
if ctx.guild is None:
|
|
52
|
+
raise CheckFailure("This command can only be used in a guild.")
|
|
53
|
+
return True
|
|
54
|
+
return check(predicate)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def dm_only():
|
|
58
|
+
"""Check that the command is used in a DM."""
|
|
59
|
+
def predicate(ctx):
|
|
60
|
+
if ctx.guild is not None:
|
|
61
|
+
raise CheckFailure("This command can only be used in DMs.")
|
|
62
|
+
return True
|
|
63
|
+
return check(predicate)
|
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Cog (extension) system for organizing commands and listeners.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import inspect
|
|
6
|
-
from typing import Callable
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class CogMeta(type):
|
|
10
|
-
"""Metaclass that auto-collects commands and listeners from cog classes."""
|
|
11
|
-
|
|
12
|
-
def __new__(mcs, name, bases, namespace):
|
|
13
|
-
cls = super().__new__(mcs, name, bases, namespace)
|
|
14
|
-
cls._commands = []
|
|
15
|
-
cls._listeners = []
|
|
16
|
-
|
|
17
|
-
for attr_name, value in namespace.items():
|
|
18
|
-
if hasattr(value, "_command"):
|
|
19
|
-
cls._commands.append(value._command)
|
|
20
|
-
if hasattr(value, "_listener"):
|
|
21
|
-
cls._listeners.append((value._listener_event, value, attr_name))
|
|
22
|
-
|
|
23
|
-
return cls
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class Cog(metaclass=CogMeta):
|
|
27
|
-
"""
|
|
28
|
-
Base class for cogs (extensions).
|
|
29
|
-
|
|
30
|
-
Group related commands and event listeners in a class.
|
|
31
|
-
Supports hot-loading and hot-unloading.
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(self, bot):
|
|
35
|
-
self.bot = bot
|
|
36
|
-
|
|
37
|
-
@property
|
|
38
|
-
def name(self) -> str:
|
|
39
|
-
return self.__class__.__name__
|
|
40
|
-
|
|
41
|
-
def _inject(self, bot):
|
|
42
|
-
"""Register this cog's commands and listeners with the bot."""
|
|
43
|
-
import logging
|
|
44
|
-
logger = logging.getLogger(__name__)
|
|
45
|
-
self.__bound_listeners__ = []
|
|
46
|
-
for cmd in self._commands:
|
|
47
|
-
cmd._cog = self
|
|
48
|
-
bot.add_command(cmd)
|
|
49
|
-
logger.debug("[cog] registered command: %s", cmd.name)
|
|
50
|
-
for event, listener, attr_name in self._listeners:
|
|
51
|
-
bound = getattr(self, attr_name)
|
|
52
|
-
bot.add_listener(event, bound)
|
|
53
|
-
self.__bound_listeners__.append((event, bound))
|
|
54
|
-
logger.info("[cog] registered listener: %s -> %s", event, attr_name)
|
|
55
|
-
return self
|
|
56
|
-
|
|
57
|
-
def _eject(self, bot):
|
|
58
|
-
"""Unregister this cog's commands and listeners from the bot."""
|
|
59
|
-
for cmd in self._commands:
|
|
60
|
-
bot.remove_command(cmd.name)
|
|
61
|
-
for alias in cmd.aliases:
|
|
62
|
-
bot.remove_command(alias)
|
|
63
|
-
for event, bound in getattr(self, "__bound_listeners__", []):
|
|
64
|
-
bot.remove_listener(event, bound)
|
|
65
|
-
return self
|
|
66
|
-
|
|
67
|
-
def cog_load(self):
|
|
68
|
-
"""Called when the cog is loaded. Override to perform setup."""
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
def cog_unload(self):
|
|
72
|
-
"""Called when the cog is unloaded. Override to perform cleanup."""
|
|
73
|
-
pass
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def listener(name: str | None = None):
|
|
77
|
-
"""Decorator to mark a method as an event listener."""
|
|
78
|
-
def decorator(func: Callable):
|
|
79
|
-
func._listener = True
|
|
80
|
-
func._listener_event = name or func.__name__.replace("on_", "", 1).upper()
|
|
81
|
-
return func
|
|
82
|
-
return decorator
|
|
1
|
+
"""
|
|
2
|
+
Cog (extension) system for organizing commands and listeners.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
from typing import Callable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CogMeta(type):
|
|
10
|
+
"""Metaclass that auto-collects commands and listeners from cog classes."""
|
|
11
|
+
|
|
12
|
+
def __new__(mcs, name, bases, namespace):
|
|
13
|
+
cls = super().__new__(mcs, name, bases, namespace)
|
|
14
|
+
cls._commands = []
|
|
15
|
+
cls._listeners = []
|
|
16
|
+
|
|
17
|
+
for attr_name, value in namespace.items():
|
|
18
|
+
if hasattr(value, "_command"):
|
|
19
|
+
cls._commands.append(value._command)
|
|
20
|
+
if hasattr(value, "_listener"):
|
|
21
|
+
cls._listeners.append((value._listener_event, value, attr_name))
|
|
22
|
+
|
|
23
|
+
return cls
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Cog(metaclass=CogMeta):
|
|
27
|
+
"""
|
|
28
|
+
Base class for cogs (extensions).
|
|
29
|
+
|
|
30
|
+
Group related commands and event listeners in a class.
|
|
31
|
+
Supports hot-loading and hot-unloading.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, bot):
|
|
35
|
+
self.bot = bot
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def name(self) -> str:
|
|
39
|
+
return self.__class__.__name__
|
|
40
|
+
|
|
41
|
+
def _inject(self, bot):
|
|
42
|
+
"""Register this cog's commands and listeners with the bot."""
|
|
43
|
+
import logging
|
|
44
|
+
logger = logging.getLogger(__name__)
|
|
45
|
+
self.__bound_listeners__ = []
|
|
46
|
+
for cmd in self._commands:
|
|
47
|
+
cmd._cog = self
|
|
48
|
+
bot.add_command(cmd)
|
|
49
|
+
logger.debug("[cog] registered command: %s", cmd.name)
|
|
50
|
+
for event, listener, attr_name in self._listeners:
|
|
51
|
+
bound = getattr(self, attr_name)
|
|
52
|
+
bot.add_listener(event, bound)
|
|
53
|
+
self.__bound_listeners__.append((event, bound))
|
|
54
|
+
logger.info("[cog] registered listener: %s -> %s", event, attr_name)
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def _eject(self, bot):
|
|
58
|
+
"""Unregister this cog's commands and listeners from the bot."""
|
|
59
|
+
for cmd in self._commands:
|
|
60
|
+
bot.remove_command(cmd.name)
|
|
61
|
+
for alias in cmd.aliases:
|
|
62
|
+
bot.remove_command(alias)
|
|
63
|
+
for event, bound in getattr(self, "__bound_listeners__", []):
|
|
64
|
+
bot.remove_listener(event, bound)
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
def cog_load(self):
|
|
68
|
+
"""Called when the cog is loaded. Override to perform setup."""
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
def cog_unload(self):
|
|
72
|
+
"""Called when the cog is unloaded. Override to perform cleanup."""
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def listener(name: str | None = None):
|
|
77
|
+
"""Decorator to mark a method as an event listener."""
|
|
78
|
+
def decorator(func: Callable):
|
|
79
|
+
func._listener = True
|
|
80
|
+
func._listener_event = name or func.__name__.replace("on_", "", 1).upper()
|
|
81
|
+
return func
|
|
82
|
+
return decorator
|