|
| 1 | +from typing import Dict |
| 2 | +import logging |
1 | 3 | import pathlib |
2 | 4 |
|
3 | | -APPLICATION_DIRECTORY = pathlib.Path(__file__).resolve().absolute().parent |
4 | | -CLI_DIRECTORY = APPLICATION_DIRECTORY.joinpath("cli") |
5 | | -CONFIGURATION_DIRECTORY = APPLICATION_DIRECTORY.joinpath("configuration") |
6 | | -MIDDLEWARE_DIRECTORY = APPLICATION_DIRECTORY.joinpath("middleware") |
7 | | -VIEWS_DIRECTORY = APPLICATION_DIRECTORY.joinpath("views") |
| 5 | +from sanic import Sanic |
| 6 | + |
| 7 | +from biothings_annotator.application.exceptions import build_exception_handers |
| 8 | +from biothings_annotator.application.middleware import build_middleware |
| 9 | +from biothings_annotator.application.static import build_static_routes, build_static_content |
| 10 | +from biothings_annotator.application.views import build_routes |
| 11 | + |
| 12 | +logging.basicConfig() |
| 13 | +logger = logging.getLogger("sanic-application") |
| 14 | +logger.setLevel(logging.DEBUG) |
| 15 | + |
| 16 | + |
| 17 | +def build_application(configuration: Dict = None) -> Sanic: |
| 18 | + """ |
| 19 | + Generates and returns an instance of the sanic.app.Sanic application |
| 20 | + for the web server |
| 21 | +
|
| 22 | + ***BEGIN IMPORTANT*** |
| 23 | + This must be kept separate from the AnnotatorCLI class methods. If you attempt |
| 24 | + to leverage this as a class method, when the worker manager attempts to spawn |
| 25 | + a process to call the partially initialized factory method, it will attempt |
| 26 | + to pickle the instances of the class itself. So unless we take the effort |
| 27 | + to make the class instance pickleable, we keep this target here for the moment |
| 28 | + ***END IMPORTANT*** |
| 29 | +
|
| 30 | + The sanic.web.Sanic application has the following constructor: |
| 31 | + https://sanic.dev/api/sanic.app.html#getting-started |
| 32 | + class Sanic( |
| 33 | + name: str, |
| 34 | + config: Optional[config_type] = None, |
| 35 | + ctx: Optional[ctx_type] = None, |
| 36 | + router: Optional[Router] = None, |
| 37 | + signal_router: Optional[SignalRouter] = None, |
| 38 | + error_handler: Optional[ErrorHandler] = None, |
| 39 | + env_prefix: Optional[str] = SANIC_, |
| 40 | + request_class: Optional[Type[Request]] = None, |
| 41 | + strict_slashes: bool = False, |
| 42 | + log_config: Optional[Dict[str, Any]] = None, |
| 43 | + configure_logging: bool = True, |
| 44 | + dumps: Optional[Callable[..., AnyStr]] = None, |
| 45 | + loads: Optional[Callable[..., Any]] = None, |
| 46 | + inspector: bool = False, |
| 47 | + inspector_class: Optional[Type[Inspector]] = None, |
| 48 | + certloader_class: Optional[Type[CertLoader]] = None |
| 49 | + ) |
| 50 | +
|
| 51 | + Loads the following additional aspects for the webserver: |
| 52 | + > routes |
| 53 | + > middleware |
| 54 | + > exception handlers |
| 55 | + """ |
| 56 | + application_configuration = configuration["application"]["configuration"] |
| 57 | + extension_configuration = configuration["application"]["extension"] |
| 58 | + |
| 59 | + configuration_settings = {} |
| 60 | + configuration_settings.update(application_configuration) |
| 61 | + configuration_settings.update(extension_configuration["cors"]) |
| 62 | + |
| 63 | + application = Sanic(name="biothings-annotator") |
| 64 | + application.update_config(configuration_settings) |
| 65 | + |
| 66 | + application_routes = build_routes() |
| 67 | + static_routes = build_static_routes() |
| 68 | + for route in (*application_routes, *static_routes): |
| 69 | + try: |
| 70 | + application.add_route(**route) |
| 71 | + except Exception as gen_exc: |
| 72 | + logger.exception(gen_exc) |
| 73 | + logger.error("Unable to add route %s", route) |
| 74 | + raise gen_exc |
| 75 | + |
| 76 | + static_content = build_static_content() |
| 77 | + for static_entry in static_content: |
| 78 | + try: |
| 79 | + application.static(static_entry[0], static_entry[1]) |
| 80 | + except Exception as gen_exc: |
| 81 | + logger.exception(gen_exc) |
| 82 | + logger.error("Unable to add static content %s", static_entry) |
| 83 | + raise gen_exc |
| 84 | + |
| 85 | + application_middleware = build_middleware() |
| 86 | + for middleware in application_middleware: |
| 87 | + try: |
| 88 | + application.register_middleware(**middleware) |
| 89 | + except Exception as gen_exc: |
| 90 | + logger.exception(gen_exc) |
| 91 | + logger.error("Unable to add middleware %s", middleware) |
| 92 | + raise gen_exc |
| 93 | + |
| 94 | + exception_handlers = build_exception_handers() |
| 95 | + for exception_handler in exception_handlers: |
| 96 | + try: |
| 97 | + application.error_handler.add(**exception_handler) |
| 98 | + except Exception as gen_exc: |
| 99 | + logger.exception(gen_exc) |
| 100 | + logger.error("Unable to add exception handler %s", exception_handler) |
| 101 | + raise gen_exc |
| 102 | + |
| 103 | + return application |
0 commit comments