Source code for aiopluggy.hooks

import inspect
import warnings

from .helpers import fqn
from .markers import HookimplMarker, HookspecMarker


[docs]class HookCallError(Exception): """ Hook was called wrongly. """
class HookSpec(object): def __init__(self, namespace, name, flag_set): self.namespace = namespace self.name = name self.function = getattr(namespace, name) self.is_first_notnone = self.is_first_only = self.is_replay = \ self.is_required = self.is_sync = False self.__dict__.update(HookspecMarker.set2dict(flag_set)) self.__init_args() def __init_args(self): signature = inspect.signature(self.function) parameters = list(signature.parameters.values()) if inspect.isclass(self.namespace) and inspect.isfunction(self.function): parameters = parameters[1:] if any(parameter.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD # not in self._ALLOWED_PARAMETER_KINDS for parameter in parameters): raise ValueError( "%s.%s%s: Only positional arguments allowed " "for hook specifications." % (fqn(self.namespace), self.name, signature) ) self.req_args = { p.name for p in parameters if p.default is inspect.Parameter.empty # p.kind == inspect.Parameter.POSITIONAL_ONLY } self.opt_args = { p.name: p.default for p in parameters if p.default is not inspect.Parameter.empty # p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD } def __str__(self): return "%s.%s%s" % ( fqn(self.namespace), self.name, inspect.signature(self.function) )
[docs]class HookValidationError(Exception): """ Plugin failed validation. """
class HookImpl(object): _ALLOWED_PARAMETER_KINDS = { inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD } def __init__(self, plugin, name, flag_set): self.plugin = plugin self.name = name self.function = getattr(plugin, name) self.is_try_first = self.is_try_last = self.is_dont_await = self.is_before = False self.__dict__.update(HookimplMarker.set2dict(flag_set)) # noinspection PyUnresolvedReferences self.is_async = (inspect.iscoroutinefunction(self.function) and not self.is_dont_await) self.__init_args() def __init_args(self): signature = inspect.signature(self.function) parameters = list(signature.parameters.values()) if any(parameter.kind != inspect.Parameter.POSITIONAL_OR_KEYWORD # not in self._ALLOWED_PARAMETER_KINDS for parameter in parameters): raise ValueError( "%s.%s%s: Only positional arguments allowed " "for hook specifications." % (fqn(self.plugin), self.name, signature) ) self.req_args = { p.name for p in parameters if p.default is inspect.Parameter.empty # p.kind == inspect.Parameter.POSITIONAL_ONLY } self.opt_args = { p.name: p.default for p in parameters if p.default is not inspect.Parameter.empty # p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD } def filtered_args(self, kwargs): return { name: value for (name, value) in kwargs.items() if name in self.req_args or name in self.opt_args } def validate_against(self, spec: HookSpec): # positional arg checking notinspec = self.req_args - spec.req_args - \ set(spec.opt_args.keys()) if notinspec: raise HookValidationError( "%s.%s: required argument(s) %s in the hook function " "are not in the hook specification." % (fqn(self.plugin), self.name, notinspec) ) for arg_name, default_value in self.opt_args.items(): if arg_name in spec.opt_args and \ default_value != spec.opt_args[arg_name]: warnings.warn( "Hook function %s.%s: optional argument '%s' has other " "default value than the corresponding hook specification." % (fqn(self.plugin), self.name, arg_name) ) # noinspection PyUnresolvedReferences if self.is_async and spec.is_sync: raise HookValidationError( "%s.%s: asynchronous hook function not allowod by hook spec." % (fqn(self.plugin), self.name) ) def __str__(self): return "%s.%s%s" % ( fqn(self.plugin), self.name, inspect.signature(self.function) )