class Starlette: def __init__(self, debug: bool = False) -> None: self.router = Router(routes=[]) self.lifespan_handler = LifespanHandler() self.app = self.router self.exception_middleware = ExceptionMiddleware(self.router, debug=debug) self.executor = ThreadPoolExecutor() @property def debug(self) -> bool: return self.exception_middleware.debug @debug.setter def debug(self, value: bool) -> None: self.exception_middleware.debug = value def on_event(self, event_type: str) -> typing.Callable: return self.lifespan_handler.on_event(event_type) def mount(self, path: str, app: ASGIApp, methods: typing.Sequence[str] = None) -> None: prefix = PathPrefix(path, app=app, methods=methods) self.router.routes.append(prefix) def add_middleware(self, middleware_class: type, **kwargs: typing.Any) -> None: self.exception_middleware.app = middleware_class(self.app, **kwargs) def add_exception_handler(self, exc_class: type, handler: typing.Callable) -> None: self.exception_middleware.add_exception_handler(exc_class, handler) def add_route(self, path: str, route: typing.Callable, methods: typing.Sequence[str] = None) -> None: if not inspect.isclass(route): route = request_response(route) if methods is None: methods = ("GET", ) instance = Path(path, route, protocol="http", methods=methods) self.router.routes.append(instance) def add_websocket_route(self, path: str, route: typing.Callable) -> None: if not inspect.isclass(route): route = websocket_session(route) instance = Path(path, route, protocol="websocket") self.router.routes.append(instance) def exception_handler(self, exc_class: type) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_exception_handler(exc_class, func) return func return decorator def route(self, path: str, methods: typing.Sequence[str] = None) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_route(path, func, methods=methods) return func return decorator def websocket_route(self, path: str) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_websocket_route(path, func) return func return decorator def __call__(self, scope: Scope) -> ASGIInstance: scope["app"] = self scope["executor"] = self.executor if scope["type"] == "lifespan": return self.lifespan_handler(scope) return self.exception_middleware(scope)
class Starlette: def __init__(self, debug: bool = False, template_directory: str = None) -> None: self._debug = debug self.router = Router() self.lifespan_handler = LifespanHandler() self.exception_middleware = ExceptionMiddleware(self.router, debug=debug) self.error_middleware = ServerErrorMiddleware( self.exception_middleware, debug=debug) self.schema_generator = None # type: typing.Optional[BaseSchemaGenerator] self.template_env = self.load_template_env(template_directory) @property def routes(self) -> typing.List[BaseRoute]: return self.router.routes @property def debug(self) -> bool: return self._debug @debug.setter def debug(self, value: bool) -> None: self._debug = value self.exception_middleware.debug = value self.error_middleware.debug = value def load_template_env(self, template_directory: str = None) -> typing.Any: if template_directory is None: return None # Import jinja2 lazily. import jinja2 @jinja2.contextfunction def url_for(context: dict, name: str, **path_params: typing.Any) -> str: request = context["request"] return request.url_for(name, **path_params) loader = jinja2.FileSystemLoader(str(template_directory)) env = jinja2.Environment(loader=loader, autoescape=True) env.globals["url_for"] = url_for return env def get_template(self, name: str) -> typing.Any: return self.template_env.get_template(name) @property def schema(self) -> dict: assert self.schema_generator is not None return self.schema_generator.get_schema(self.routes) def on_event(self, event_type: str) -> typing.Callable: return self.lifespan_handler.on_event(event_type) def mount(self, path: str, app: ASGIApp, name: str = None) -> None: self.router.mount(path, app=app, name=name) def add_middleware(self, middleware_class: type, **kwargs: typing.Any) -> None: self.error_middleware.app = middleware_class(self.error_middleware.app, **kwargs) def add_exception_handler( self, exc_class_or_status_code: typing.Union[int, typing.Type[Exception]], handler: typing.Callable, ) -> None: if exc_class_or_status_code in (500, Exception): self.error_middleware.handler = handler else: self.exception_middleware.add_exception_handler( exc_class_or_status_code, handler) def add_event_handler(self, event_type: str, func: typing.Callable) -> None: self.lifespan_handler.add_event_handler(event_type, func) def add_route( self, path: str, route: typing.Callable, methods: typing.List[str] = None, name: str = None, include_in_schema: bool = True, ) -> None: self.router.add_route(path, route, methods=methods, name=name) def add_websocket_route(self, path: str, route: typing.Callable, name: str = None) -> None: self.router.add_websocket_route(path, route, name=name) def exception_handler( self, exc_class_or_status_code: typing.Union[int, typing.Type[Exception]] ) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_exception_handler(exc_class_or_status_code, func) return func return decorator def route( self, path: str, methods: typing.List[str] = None, name: str = None, include_in_schema: bool = True, ) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.router.add_route( path, func, methods=methods, name=name, include_in_schema=include_in_schema, ) return func return decorator def websocket_route(self, path: str, name: str = None) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.router.add_websocket_route(path, func, name=name) return func return decorator def middleware(self, middleware_type: str) -> typing.Callable: assert (middleware_type == "http" ), 'Currently only middleware("http") is supported.' def decorator(func: typing.Callable) -> typing.Callable: self.add_middleware(BaseHTTPMiddleware, dispatch=func) return func return decorator def url_path_for(self, name: str, **path_params: str) -> URLPath: return self.router.url_path_for(name, **path_params) def __call__(self, scope: Scope) -> ASGIInstance: scope["app"] = self if scope["type"] == "lifespan": return self.lifespan_handler(scope) return self.error_middleware(scope)
class Starlette: def __init__(self, debug: bool = False) -> None: self.router = Router() self.lifespan_handler = LifespanHandler() self.app = self.router self.exception_middleware = ExceptionMiddleware(self.router, debug=debug) @property def routes(self) -> typing.List[BaseRoute]: return self.router.routes @property def debug(self) -> bool: return self.exception_middleware.debug @debug.setter def debug(self, value: bool) -> None: self.exception_middleware.debug = value def on_event(self, event_type: str) -> typing.Callable: return self.lifespan_handler.on_event(event_type) def mount(self, path: str, app: ASGIApp) -> None: self.router.mount(path, app=app) def add_middleware(self, middleware_class: type, **kwargs: typing.Any) -> None: self.exception_middleware.app = middleware_class(self.app, **kwargs) def add_exception_handler(self, exc_class: type, handler: typing.Callable) -> None: self.exception_middleware.add_exception_handler(exc_class, handler) def add_event_handler(self, event_type: str, func: typing.Callable) -> None: self.lifespan_handler.add_event_handler(event_type, func) def add_route( self, path: str, route: typing.Callable, methods: typing.List[str] = None ) -> None: self.router.add_route(path, route, methods=methods) def add_graphql_route(self, path: str, schema: typing.Any) -> None: self.router.add_graphql_route(path, schema) def add_websocket_route(self, path: str, route: typing.Callable) -> None: self.router.add_websocket_route(path, route) def exception_handler(self, exc_class: type) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.add_exception_handler(exc_class, func) return func return decorator def route(self, path: str, methods: typing.List[str] = None) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.router.add_route(path, func, methods=methods) return func return decorator def websocket_route(self, path: str) -> typing.Callable: def decorator(func: typing.Callable) -> typing.Callable: self.router.add_websocket_route(path, func) return func return decorator def url_path_for(self, name: str, **path_params: str) -> URL: return self.router.url_path_for(name, **path_params) def __call__(self, scope: Scope) -> ASGIInstance: scope["app"] = self scope["router"] = self.router if scope["type"] == "lifespan": return self.lifespan_handler(scope) return self.exception_middleware(scope)