diff --git a/commands/command_base.py b/commands/command_base.py new file mode 100644 index 0000000..569f9a0 --- /dev/null +++ b/commands/command_base.py @@ -0,0 +1,24 @@ +from abc import ABCMeta, abstractmethod + + +class AbstractCommand(metaclass=ABCMeta): + """ + This is the base class for commands. In order to load a command a few conditions must be met: + 1) The class name MUST begin with 'Command' i.e. CommandTTS, CommandBan, etc... + 2) the class MUST extend AbstractCommand + + Generally, it would be advisable to define the command (something like !so, !tts, !songrequest) as a variable of the + class and to then call super().__init__(command) + """ + def __init__(self, command: str): + self.command = command + + def honk(self): + print("Success! %s" % self.command) + + def get_command(self) -> str: + return self.command + + @abstractmethod + def do_command(self, fulltext): + pass diff --git a/commands/implemented/command_tts.py b/commands/implemented/command_tts.py new file mode 100644 index 0000000..c172cea --- /dev/null +++ b/commands/implemented/command_tts.py @@ -0,0 +1,15 @@ +from abc import ABCMeta + +from commands.command_base import AbstractCommand + + +class CommandTTS(AbstractCommand, metaclass=ABCMeta): + + command = "!tts" + + def __init__(self): + super().__init__(CommandTTS.command) + + def do_command(self, fulltext): + print(fulltext) + diff --git a/commands/loader.py b/commands/loader.py new file mode 100644 index 0000000..38c3685 --- /dev/null +++ b/commands/loader.py @@ -0,0 +1,88 @@ +import importlib +import importlib.util +import inspect +import os +import sys + +from commands.command_base import AbstractCommand + + +def load_commands() -> dict: + clear_compiled() + commands = compile_and_load() + return commands + + +def compile_and_load_file(path: str) -> (str, AbstractCommand): + module_name = os.path.split(path)[1].replace(".py", "") + spec = importlib.util.spec_from_file_location(module_name, path) + module = importlib.util.module_from_spec(spec) + sys.modules[module_name] = module + spec.loader.load_module(module_name) + + for name, obj in inspect.getmembers(module): + if inspect.isclass(obj) and name.startswith("Command"): + command_inst = obj() + print("Successfully loaded %s: %s" % (name, command_inst.get_command())) + return command_inst.get_command(), command_inst + return "", None + + +def compile_and_load() -> dict: + dic = {} + compiled_path = get_implementations_dir() + for dirName, subdirList, fileList in os.walk(compiled_path): + for file in fileList: + name = os.path.join(dirName, file) + print("compiling %s" % name) + name, command = compile_and_load_file(name) + dic[name] = command + break + return dic + + +def clear_compiled(): + compiled_path = get_compiled_dir() + for dirName, subdirList, fileList in os.walk(compiled_path): + for file in fileList: + name = os.path.join(dirName, file) + os.remove(name) + break + + +def get_base_dir(): + cwd = os.getcwd() + split = os.path.split(cwd) + current = split[len(split) - 1] + if current == 'commands': + return check_dir(cwd) + if current == 'Praxis_Bot': + return check_dir(os.path.join(current, "commands")) + else: + print("could not find working directory for Praxis_Bot/commands") + raise + + +def script_to_pyc(path: str): + split = os.path.split(path) + current = split[len(split) - 1] + full = os.path.join(get_compiled_dir(), current + 'c') + return full + + +def get_implementations_dir(): + return check_dir(os.path.join(get_base_dir(), "implemented")) + + +def get_compiled_dir(): + return check_dir(os.path.join(get_base_dir(), "compiled")) + + +def check_dir(path: str): + if not os.path.exists(path): + os.mkdir(path, 0x777) + return path + + +if __name__ == "__main__": + load_commands()