def __new__(cls, *args, **kwargs): # making a bold assumption here. # Assuming that if a sanic plugin is initialized using # `MyPlugin(app)`, then the user is attempting to do a legacy plugin # instantiation, aka Flask-Style plugin instantiation. if args and len(args) > 0 and \ (isinstance(args[0], Sanic) or isinstance(args[0], Blueprint)): app = args[0] try: mod_name = cls.__module__ mod = importlib.import_module(mod_name) assert mod except (ImportError, AssertionError): raise RuntimeError( "Failed attempting a legacy plugin instantiation. " "Cannot find the module this plugin belongs to.") # Get the spf singleton from this app from spf.framework import SanicPluginsFramework spf = SanicPluginsFramework(app) # catch cases like when the module is "__main__" or # "__call__" or "__init__" if mod_name.startswith("__"): # In this case, we cannot use the module to register the # plugin. Try to use the class method. assoc = spf.register_plugin(cls, *args, **kwargs) else: assoc = spf.register_plugin(mod, *args, **kwargs) return assoc self = super(SanicPlugin, cls).__new__(cls) try: self._initialized # initialized may be True or Unknown except AttributeError: self._initialized = False return self
def decorate(cls, app, *args, run_middleware=False, with_context=False, **kwargs): """ This is a decorator that can be used to apply this plugin to a specific route/view on your app, rather than the whole app. :param app: :type app: Sanic | Blueprint :param args: :type args: tuple(Any) :param run_middleware: :type run_middleware: bool :param with_context: :type with_context: bool :param kwargs: :param kwargs: dict(Any) :return: the decorated route/view :rtype: fn """ from spf.framework import SanicPluginsFramework spf = SanicPluginsFramework(app) # get the singleton from the app try: assoc = spf.register_plugin(cls, skip_reg=True) except ValueError as e: # this is normal, if this plugin has been registered previously assert e.args and len(e.args) > 1 assoc = e.args[1] (plugin, reg) = assoc inst = spf.get_plugin(plugin) # plugin may not actually be registered # registered might be True, False or None at this point regd = True if inst else None if regd is True: # middleware will be run on this route anyway, because the plugin # is registered on the app. Turn it off on the route-level. run_middleware = False req_middleware = deque() resp_middleware = deque() if run_middleware: for i, m in enumerate(plugin._middlewares): attach_to = m.kwargs.pop('attach_to', 'request') priority = m.kwargs.pop('priority', 5) with_context = m.kwargs.pop('with_context', False) mw_handle_fn = m.middleware if attach_to == 'response': relative = m.kwargs.pop('relative', 'post') if relative == "pre": mw = (0, 0 - priority, 0 - i, mw_handle_fn, with_context, m.args, m.kwargs) else: # relative = "post" mw = (1, 0 - priority, 0 - i, mw_handle_fn, with_context, m.args, m.kwargs) resp_middleware.append(mw) else: # attach_to = "request" relative = m.kwargs.pop('relative', 'pre') if relative == "post": mw = (1, priority, i, mw_handle_fn, with_context, m.args, m.kwargs) else: # relative = "pre" mw = (0, priority, i, mw_handle_fn, with_context, m.args, m.kwargs) req_middleware.append(mw) req_middleware = tuple(sorted(req_middleware)) resp_middleware = tuple(sorted(resp_middleware)) def _decorator(f): nonlocal spf, plugin, regd, run_middleware, with_context nonlocal req_middleware, resp_middleware, args, kwargs async def wrapper(request, *a, **kw): nonlocal spf, plugin, regd, run_middleware, with_context nonlocal req_middleware, resp_middleware, f, args, kwargs # the plugin was not registered on the app, it might be now if regd is None: _inst = spf.get_plugin(plugin) regd = _inst is not None context = plugin.get_context_from_spf(spf) if run_middleware and not regd and len(req_middleware) > 0: for (_a, _p, _i, handler, with_context, args, kwargs) \ in req_middleware: if with_context: resp = handler(request, *args, context=context, **kwargs) else: resp = handler(request, *args, **kwargs) if isawaitable(resp): resp = await resp if resp: return response = await plugin.route_wrapper( f, request, context, a, kw, *args, with_context=with_context, **kwargs) if isawaitable(response): response = await response if run_middleware and not regd and len(resp_middleware) > 0: for (_a, _p, _i, handler, with_context, args, kwargs) \ in resp_middleware: if with_context: _resp = handler(request, response, *args, context=context, **kwargs) else: _resp = handler(request, response, *args, **kwargs) if isawaitable(_resp): _resp = await _resp if _resp: response = _resp break return response return update_wrapper(wrapper, f) return _decorator