我正在构建一个脚本运行器,因此可以很容易地重用脚本代码,但是我想让人们轻松添加更多脚本,而不必更改run-script.py
方法。理想情况下,我希望能够调用run-scripts.py <ClassName>
并使其执行类中的接口。现在,我正在测试导入功能,因此如果运行run-script.py list
,它将列出基类接口的所有实现并在其上运行功能。
我的文件夹布局如下:
run-script.py
|- a
|- script-a.py
|- script-ab.py
|- b
|- script-b.py
|- ...
|- ...
我正在利用一个抽象基类来定义接口协定,像这样:
class ScriptRunnerBaseClass(metaclass=ABCMeta):
@abstractmethod
def run(self):
pass
@abstractmethod
def description(self):
pass
然后执行这样的实现:
class AppStats(ScriptRunnerBaseClass, metaclass=ABCMeta):
def __init__(self):
pass
def description(self):
return "Here is my description!"
def run(self):
self.do_things()
在我的run-script.py
入口点中,我当前正在尝试列出抽象基类的所有实现的描述实现。我找到了article on dynamic imports,这是我到目前为止的内容。
import argparse
import gc
import importlib
import inspect
import pkgutil
import sys
from inspect import isclass
from pathlib import Path
from cloudfoundry.runner import ScriptRunnerBaseClass
class ScriptLoader(object):
ignored_locations = ["venv"]
def __init__(self):
pass
@staticmethod
def load_all():
for (_, name, _) in pkgutil.iter_modules([Path(__file__).parent]):
imported_module = importlib.import_module(name, package=__name__)
for i in dir(imported_module):
attribute = getattr(imported_module, i)
if inspect.isclass(attribute) and issubclass(attribute, ScriptRunnerBaseClass):
setattr(sys.modules[__name__], name, attribute)
def main():
parser = argparse.ArgumentParser(description="Run a script against Cloud Foundry!")
parser.add_argument("list", help="List all available cf scripts.")
args = parser.parse_args()
ScriptLoader.load_all()
if args.list:
print_scripts()
def print_scripts():
for obj in gc.get_objects():
if isclass(obj):
if issubclass(ScriptRunnerBaseClass, obj):
# AppStats: Here is my description!
print("{0}: {1}".format(obj.__name__, obj().description()))
if __name__ == "__main__":
main()
我已经验证了模块是通过REPL加载的,所以我知道ScriptLoader.load_all()
功能正在实现我想要的功能。当我运行它时,我得到TypeError
并不确定100%了解:
✗ python3 run-script.py list
Traceback (most recent call last):
File "run-script.py", line 50, in <module>
main()
File "run-script.py", line 39, in main
print_scripts()
File "run-script.py", line 46, in print_scripts
print("{0}: {1}".format(obj.__name__, obj().description()))
TypeError: Can't instantiate abstract class Hashable with abstract methods __hash__
我在做什么错?如何才能获得加载所有接口实现然后在它们上调用方法的预期结果?