aboutsummaryrefslogtreecommitdiffstats
path: root/botcore/utils/_extensions.py
diff options
context:
space:
mode:
authorGravatar ChrisJL <[email protected]>2022-04-02 20:11:34 +0100
committerGravatar GitHub <[email protected]>2022-04-02 20:11:34 +0100
commit765284a5e436f7786619a5ba4c312d75df5e9dee (patch)
treef4748800698892fc9940c217b5507011ec614d27 /botcore/utils/_extensions.py
parentMerge pull request #39 from python-discord/revert-disnake (diff)
parentUse imperative mood in docstrings (diff)
Merge pull request #42 from python-discord/bump-d.py-and-add-BotBase
Bump d.py and add bot base
Diffstat (limited to 'botcore/utils/_extensions.py')
-rw-r--r--botcore/utils/_extensions.py52
1 files changed, 52 insertions, 0 deletions
diff --git a/botcore/utils/_extensions.py b/botcore/utils/_extensions.py
new file mode 100644
index 00000000..d90a25dd
--- /dev/null
+++ b/botcore/utils/_extensions.py
@@ -0,0 +1,52 @@
+"""Utilities for loading Discord extensions."""
+
+import importlib
+import inspect
+import pkgutil
+import types
+from typing import NoReturn
+
+
+def unqualify(name: str) -> str:
+ """
+ Return an unqualified name given a qualified module/package ``name``.
+
+ Args:
+ name: The module name to unqualify.
+
+ Returns:
+ The unqualified module name.
+ """
+ return name.rsplit(".", maxsplit=1)[-1]
+
+
+def walk_extensions(module: types.ModuleType) -> frozenset[str]:
+ """
+ Return all extension names from the given module.
+
+ Args:
+ module (types.ModuleType): The module to look for extensions in.
+
+ Returns:
+ A set of strings that can be passed directly to :obj:`discord.ext.commands.Bot.load_extension`.
+ """
+
+ def on_error(name: str) -> NoReturn:
+ raise ImportError(name=name) # pragma: no cover
+
+ modules = set()
+
+ for module_info in pkgutil.walk_packages(module.__path__, f"{module.__name__}.", onerror=on_error):
+ if unqualify(module_info.name).startswith("_"):
+ # Ignore module/package names starting with an underscore.
+ continue
+
+ if module_info.ispkg:
+ imported = importlib.import_module(module_info.name)
+ if not inspect.isfunction(getattr(imported, "setup", None)):
+ # If it lacks a setup function, it's not an extension.
+ continue
+
+ modules.add(module_info.name)
+
+ return frozenset(modules)