import inspect
import functools
[docs]
class Router:
"""
This class is a singleton that provides a decorator that can be used to add methods
to a handlers router dictionary.
.. code-block:: python
from q2_sdk.core import routes
...
@property
def router(self):
router = super().router
router.update({
# if you use the ``routes`` decorator then you do not need to add route
# keys here
"default": self.default,
# "example_route": self.example_route, is added automatically
# "another_route": self.some_route, is added automatically
})
@routes.add
async def example_route(self):
# this method will be added to the routes dictionary with the key being the
# name of the method
@routes.add(name="another_route")
async def some_route(self):
# this method will be added to the routes dictionary with the key provided
# by the ``name`` parameter to ``add``
"""
_instance = None
_files = {}
def __new__(cls):
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
def __call__(self, cls):
cls_path = inspect.getfile(cls)
cls_name = cls.__name__
if cls_path in self._files:
if cls_name in self._files[cls_path]:
cls._routes.update(self._files[cls_path][cls_name])
def add(self, name=None):
def decorator(func):
route_name = (
name if name is not None and isinstance(name, str) else func.__name__
)
func_path = inspect.getfile(func)
cls_name = func.__qualname__.split(".")[0]
if func_path not in self._files:
self._files[func_path] = {}
if cls_name not in self._files[func_path]:
self._files[func_path][cls_name] = {}
self._files[func_path][cls_name][route_name] = func.__name__
@functools.wraps(func)
async def wrapper(*args, **kwargs):
return await func(*args, **kwargs)
return wrapper
if callable(name):
return decorator(name)
else:
return decorator
routes = Router()