"""The Quality-Control Web Application entry point""" import os import sys import logging from pathlib import Path from flask import Flask, request from flask_session import Session from uploader.oauth2.client import user_logged_in, authserver_authorise_uri from . import session from .base_routes import base from .files.views import files from .species import speciesbp from .oauth2.views import oauth2 from .expression_data import exprdatabp from .errors import register_error_handlers def override_settings_with_envvars( app: Flask, ignore: tuple[str, ...]=tuple()) -> None: """Override settings in `app` with those in ENVVARS""" for setting in (key for key in app.config if key not in ignore): app.config[setting] = os.environ.get(setting) or app.config[setting] def __log_gunicorn__(app: Flask) -> Flask: """Set up logging for the WSGI environment with GUnicorn""" logger = logging.getLogger("gunicorn.error") app.logger.handlers = logger.handlers app.logger.setLevel(logger.level) return app def __log_dev__(app: Flask) -> Flask: """Set up logging for the development environment.""" stderr_handler = logging.StreamHandler(stream=sys.stderr) app.logger.addHandler(stderr_handler) root_logger = logging.getLogger() root_logger.addHandler(stderr_handler) root_logger.setLevel(app.config["LOG_LEVEL"]) return app def setup_logging(app: Flask) -> Flask: """Set up logging for the application.""" software, *_version_and_comments = os.environ.get( "SERVER_SOFTWARE", "").split('/') return __log_gunicorn__(app) if bool(software) else __log_dev__(app) def create_app(): """The application factory""" app = Flask(__name__) app.config.from_pyfile( Path(__file__).parent.joinpath("default_settings.py")) if "UPLOADER_CONF" in os.environ: app.config.from_envvar("UPLOADER_CONF") # Override defaults with instance path override_settings_with_envvars(app, ignore=tuple()) secretsfile = app.config.get("UPLOADER_SECRETS", "").strip() if bool(secretsfile): secretsfile = Path(secretsfile).absolute() app.config["UPLOADER_SECRETS"] = secretsfile if secretsfile.exists(): # Silently ignore secrets if the file does not exist. app.config.from_pyfile(secretsfile) setup_logging(app) # setup jinja2 symbols app.add_template_global(lambda : request.url, name="request_url") app.add_template_global(authserver_authorise_uri) app.add_template_global(lambda: app.config["GN2_SERVER_URL"], name="gn2server_uri") app.add_template_global(user_logged_in) app.add_template_global(lambda : session.user_details()["email"], name="user_email") Session(app) # setup blueprints app.register_blueprint(base, url_prefix="/") app.register_blueprint(files, url_prefix="/files") app.register_blueprint(oauth2, url_prefix="/oauth2") app.register_blueprint(speciesbp, url_prefix="/species") register_error_handlers(app) return app