Plugin action decorators can now be inherited from parent classes

This commit is contained in:
Fabio Manganiello 2018-07-17 01:23:12 +02:00
parent 35c5e2d8f7
commit 95d86829aa
2 changed files with 26 additions and 8 deletions

View file

@ -36,7 +36,10 @@ class Plugin(object):
if 'logging' in kwargs: if 'logging' in kwargs:
self.logger.setLevel(getattr(logging, kwargs['logging'].upper())) self.logger.setLevel(getattr(logging, kwargs['logging'].upper()))
self.registered_actions = set(get_decorators(self.__class__).get('action', [])) self.registered_actions = set(
get_decorators(self.__class__, climb_class_hierarchy=True)
.get('action', [])
)
def run(self, method, *args, **kwargs): def run(self, method, *args, **kwargs):
if method not in self.registered_actions: if method not in self.registered_actions:

View file

@ -73,12 +73,16 @@ def get_hash(s):
return hashlib.sha256(s.encode('utf-8')).hexdigest() return hashlib.sha256(s.encode('utf-8')).hexdigest()
def get_decorators(cls): def get_decorators(cls, climb_class_hierarchy=False):
target = cls """
Get the decorators of a class as a {"decorator_name": [list of methods]} dictionary
:param climb_class_hierarchy: If set to True (default: False), it will search return the decorators in the parent classes as well
:type climb_class_hierarchy: bool
"""
decorators = {} decorators = {}
def visit_FunctionDef(node): def visit_FunctionDef(node):
# decorators[node.name] = []
for n in node.decorator_list: for n in node.decorator_list:
name = '' name = ''
if isinstance(n, ast.Call): if isinstance(n, ast.Call):
@ -86,13 +90,24 @@ def get_decorators(cls):
else: else:
name = n.attr if isinstance(n, ast.Attribute) else n.id name = n.attr if isinstance(n, ast.Attribute) else n.id
decorators[name] = decorators.get(name, []) decorators[name] = decorators.get(name, set())
# decorators[node.name].append(name) decorators[name].add(node.name)
decorators[name].append(node.name)
if climb_class_hierarchy:
targets = inspect.getmro(cls)
else:
targets = [cls]
node_iter = ast.NodeVisitor() node_iter = ast.NodeVisitor()
node_iter.visit_FunctionDef = visit_FunctionDef node_iter.visit_FunctionDef = visit_FunctionDef
for target in targets:
try:
node_iter.visit(ast.parse(inspect.getsource(target))) node_iter.visit(ast.parse(inspect.getsource(target)))
except TypeError:
# Ignore built-in classes
pass
return decorators return decorators