slim/base/app.py

Summary

Maintainability
A
2 hrs
Test Coverage
import logging
from typing import Optional, TYPE_CHECKING, Type

from slim.base.types.doc import ApplicationDocInfo
from slim.ext.openapi.serve import doc_serve
from .session import CookieSession
from .user import BaseUserViewMixin
from .web import handle_request, CORSOptions
from ..utils.jsdict import JsDict
from . import log

if TYPE_CHECKING:
    from .permission import Permissions

logger = logging.getLogger(__name__)


class SlimTables(JsDict):
    # key: table_name
    # value: SQLView
    def __repr__(self):
        return '<SlimTables ' + dict.__repr__(self) + '>'


class ApplicationOptions:
    def __init__(self):
        self.cookies_secret = b'secret code'
        self.session_cls = CookieSession


class Application:
    def __init__(self, *, cookies_secret: bytes = b'secret code', log_level=logging.INFO, session_cls=CookieSession,
                 mountpoint: str = '/api', doc_enable=True, doc_info=ApplicationDocInfo(),
                 permission: Optional['Permissions'] = None, client_max_size=100 * 1024 * 1024,
                 cors_options: Optional[CORSOptions] = None):
        """
        :param cookies_secret:
        :param log_level:
        :param permission: `ALL_PERMISSION`, `EMPTY_PERMISSION` or a `Permissions` object
        :param session_cls:
        :param mountpoint:
        :param doc_enable:
        :param doc_info:
        :param client_max_size: 100MB
        """
        from .route import Route
        from .permission import Permissions, Ability, ALL_PERMISSION, EMPTY_PERMISSION

        self.running = False
        self.on_startup = []
        self.on_shutdown = []

        self.user_mixin_class = None
        self.mountpoint = mountpoint
        self.route = Route(self)
        self.doc_enable = doc_enable
        self.doc_info = doc_info

        if self.doc_enable:
            doc_serve(self)

        if permission is ALL_PERMISSION:
            logger.warning('app.permission is ALL_PERMISSION, it means everyone has all permissions for any table')
            logger.warning("This option should only be used in development environment")
            self.permission = Permissions(self)
            self.permission.add(None, Ability({'*': '*'}))  # everyone has all permission for all table
        elif permission is None or permission is EMPTY_PERMISSION:
            self.permission = Permissions(self)  # empty
        else:
            self.permission = permission
            permission.app = self

        self.tables = SlimTables()

        if log_level:
            log.enable(log_level)

        if isinstance(cors_options, CORSOptions):
            self.cors_options = [cors_options]
        else:
            self.cors_options = cors_options

        self.options = ApplicationOptions()
        self.options.cookies_secret = cookies_secret
        self.options.session_cls = session_cls
        self.client_max_size = client_max_size

        self._timers_before_running = []
        self._last_view = None  # use for tests
        self._last_resp = None  # use for tests

    def prepare(self):
        self.route._bind()

    async def __call__(self, scope, receive, send, *, raise_for_resp=False):
        await handle_request(self, scope, receive, send, raise_for_resp=raise_for_resp)

    def set_user_mixin_class(self, cls: Type[BaseUserViewMixin]):
        self.user_mixin_class = cls

    def run(self, host, port):
        import uvicorn
        logger.info(f'Running on http://{host}:{port}')
        logger.info('(Press CTRL+C to quit)')
        uvicorn.run(self, host=host, port=port, log_level='error')