Passed
Pull Request — main (#389)
by
unknown
02:23
created

pincer.cog.CogManager.load_module()   B

Complexity

Conditions 6

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 13
rs 8.6666
c 0
b 0
f 0
cc 6
nop 2
1
# Copyright Pincer 2021-Present
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# Full MIT License can be found in `LICENSE` at the project root.
3
4
from __future__ import annotations
5
from asyncio import ensure_future
6
7
from importlib import reload, import_module
8
from inspect import isclass
9
from types import ModuleType
10
from typing import TYPE_CHECKING, List
11
12
from . import client as _client
0 ignored issues
show
Unused Code introduced by
Unused client imported as _client
Loading history...
13
from .commands.chat_command_handler import ChatCommandHandler
14
from .commands.interactable import Interactable
15
from .exceptions import CogAlreadyExists, CogNotFound
0 ignored issues
show
Unused Code introduced by
Unused CogNotFound imported from exceptions
Loading history...
16
17
if TYPE_CHECKING:
18
    from typing import Type
19
    from .client import Client
20
21
22
class CogManager:
23
    """
24
    A class that can load and unload cogs
25
    """
26
27
    def load_cog(self, cog: Type[Cog]):
28
        """Load a cog from a string path, setup method in COG may
29
        optionally have a first argument which will contain the client!
30
31
        :Example usage:
32
33
        run.py
34
35
        .. code-block:: python3
36
37
             from pincer import Client
38
             from cogs.say import SayCommand
39
40
             class MyClient(Client):
41
                 def __init__(self, *args, **kwargs):
42
                     self.load_cog(SayCommand)
43
                     super().__init__(*args, **kwargs)
44
45
        cogs/say.py
46
47
        .. code-block:: python3
48
49
             from pincer import command
50
51
             class SayCommand(Cog):
52
                 @command()
53
                 async def say(self, message: str) -> str:
54
                     return message
55
56
        Parameters
57
        ----------
58
        cog : Type[:class:`~pincer.cog.Cog`]
59
            The cog to load.
60
        """
61
        if cog in ChatCommandHandler.managers:
62
            raise CogAlreadyExists(
63
                f"Cog `{cog}` is trying to be loaded but already exists."
64
            )
65
66
        cog_manager = cog(self)
67
68
        ChatCommandHandler.managers.append(cog_manager)
69
70
    def load_cogs(self, *cogs: Type[Cog]):
71
        """
72
        Loads a list of cogs
73
74
        Parameters
75
        ----------
76
        \\*cogs : Type[:class:`~pincer.cog.Cog`]
77
            A list of cogs to load.
78
        """
79
        for cog in cogs:
80
            self.load_cog(cog)
81
82
    def load_module(self, module: ModuleType):
83
        """Loads the cogs from a module recursively.
84
85
        Parameters
86
        ----------
87
        module : :class:`~types.ModuleType`
88
            The module to load.
89
        """
90
        for item in vars(module).values():
91
            if isinstance(item, ModuleType):
92
                self.load_module(item)
93
            elif item is not Cog and isclass(item) and issubclass(item, Cog):
94
                self.load_cog(item)
95
96
    def reload_cogs(self):
97
        """Reloads all of the loaded cogs"""
98
99
        modules = []
100
101
        for cog in self.cogs:
102
            cog.unassign()
103
104
            mod = import_module(type(cog).__module__)
105
            if mod not in modules:
106
                modules.append(mod)
107
108
        for mod in modules:
109
            self.load_module(reload(mod))
110
111
        ChatCommandHandler.has_been_initialized = False
112
        ensure_future(ChatCommandHandler(self).initialize())
113
114
    @property
115
    def cogs(self) -> List[Cog]:
116
        """Get a dictionary of all loaded cogs.
117
118
        The key/value pair is import path/cog class.
119
120
        Returns
121
        -------
122
        List[:class:`~pincer.cog.Cog`]
123
            The list of cogs
124
        """
125
        return [
126
            manager for manager in ChatCommandHandler.managers
127
            if isinstance(manager, Cog)
128
        ]
129
130
131
class Cog(Interactable):
132
    """A cog object
133
    This is an object that can register commands and message components that isn't a
134
    client. It also can be loaded and unloaded at runtime so commands can be changed
135
    without restarting the bot.
136
    """
137
138
    def __init__(self, client: Client) -> None:
139
        self.client = client
140
141
        super().__init__()
142
143
    @classmethod
144
    def name(cls) -> str:
145
        """
146
        Returns a unique name for this cog.
147
148
        Returns
149
        -------
150
        str
151
            A unique name for this cog.
152
        """
153
        return f"{cls.__module__}.{cls.__name__}"
154