implemented class loader for concrete instances of commands

This commit is contained in:
dtookey 2020-10-02 12:30:47 -04:00
parent 70cbb2ca9a
commit 0e53eedfba
3 changed files with 127 additions and 0 deletions

24
commands/command_base.py Normal file
View File

@ -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

View File

@ -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)

88
commands/loader.py Normal file
View File

@ -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()