diff options
author | 2022-02-22 23:47:09 +0000 | |
---|---|---|
committer | 2022-02-24 17:32:47 +0000 | |
commit | 060bad105dc2569fc485adb03b985aa2ab5d367e (patch) | |
tree | 05b218472ee306d1d2faeb121a21c1e2d6de9fe7 /botcore/utils/extensions.py | |
parent | Add markdown powered changelog (diff) |
Move new utilities to the util namespace
Diffstat (limited to 'botcore/utils/extensions.py')
-rw-r--r-- | botcore/utils/extensions.py | 52 |
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..c8f200ad --- /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]: + """ + Yield extension names from the bot.exts subpackage. + + 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) |