Module app.main

A Flask layer to haystack interface.

Expand source code
# -*- coding: utf-8 -*-
# Haystack API Provider module
# See the accompanying LICENSE file.
# (C) 2021 Engie Digital
#
# vim: set ts=4 sts=4 et tw=78 sw=4 si:
"""
A Flask layer to haystack interface.
"""
import logging
import os
import sys

import click
from flask import Flask, send_from_directory

from shaystack.providers import get_provider

try:
    from flask_cors import CORS
    from app.blueprint_haystack import create_haystack_bp
except ImportError as ex:
    print('To start shift-4-haystack, use \'pip install "shaystack[flask]"\' or '
          '\'pip install "shaystack[flask,graphql]"\' and set \'HAYSTACK_PROVIDER\' variable',
          file=sys.stderr)
    sys.exit(-1)

USE_GRAPHQL = False
try:
    import graphene  # pylint: disable=unused-import
    from app.blueprint_graphql import create_graphql_bp  # pylint: disable=ungrouped-imports

    USE_GRAPHQL = True
except ImportError:
    USE_GRAPHQL = False

_log_level = os.environ.get("LOG_LEVEL", "WARNING")
logging.basicConfig(level=_log_level)


def init_app(app: Flask) -> Flask:
    @app.route('/')
    def index():
        """Empty page to check the deployment"""
        redirect_js = """
        <script>
        if (! window.location.pathname.toString().endsWith("/")) {
          document.location.href=window.location+"/"; 
        }
        </script>
        """
        if USE_GRAPHQL:
            return f"""
                {redirect_js}
                <body>
                <a href="haystack">Haystack API</a><br />
                <a href="graphql">Haystack GraphQL API</a><br />
                </body>
                """
        return f"""
            {redirect_js}
            <body>
            <a href="haystack">Haystack API</a><br />
            </body>
            """

    @app.route('/favicon.ico')
    def favicon():
        """Return the favorite icon"""
        return send_from_directory(os.path.join(app.root_path, 'static'),
                                   'favicon.ico', mimetype='image/vnd.microsoft.icon')

    app.logger.setLevel(_log_level)  # pylint: disable=no-member
    return app


def add_blueprints(app: Flask) -> Flask:
    provider_name = os.environ.get("HAYSTACK_PROVIDER", "shaystack.providers.db")
    provider = get_provider(provider_name, os.environ)
    app.register_blueprint(create_haystack_bp(provider))
    if USE_GRAPHQL:
        app.register_blueprint(create_graphql_bp(provider))
    CORS(app, resources={
        r"/haystack/*": {"origins": "*"},
        r"/graphql/*": {"origins": "*"}}, )
    return app


def create_app() -> Flask:
    return add_blueprints(init_app(Flask(__name__)))


def start_shaystack(host: str, port: int, app: Flask) -> int:
    """Stack a flask server. The command line must set the host and port.

    Args:

        app: Flask app instance
        host: Network to listen (0.0.0.0 to accept call from all network)
        port: Port to listen

    Envs:

        HAYSTACK_PROVIDER: to select a provider (shaystack.providers.db)
        HAYSTACK_DB: the URL to select the backend with the ontology
    """
    debug = (os.environ.get("FLASK_DEBUG", "0") == "1")
    app.run(host=host,
            port=port,
            debug=debug)
    return 0


app_instance = create_app()


@click.command()
@click.option('-h', '--host', default='localhost')
@click.option('-p', '--port', default=3000, type=int)
def main(host, port):
    return start_shaystack(host, port, app_instance)


if __name__ == '__main__':
    sys.exit(main())  # pylint: disable=no-value-for-parameter,unexpected-keyword-arg

Functions

def add_blueprints(app: flask.app.Flask) ‑> flask.app.Flask
Expand source code
def add_blueprints(app: Flask) -> Flask:
    provider_name = os.environ.get("HAYSTACK_PROVIDER", "shaystack.providers.db")
    provider = get_provider(provider_name, os.environ)
    app.register_blueprint(create_haystack_bp(provider))
    if USE_GRAPHQL:
        app.register_blueprint(create_graphql_bp(provider))
    CORS(app, resources={
        r"/haystack/*": {"origins": "*"},
        r"/graphql/*": {"origins": "*"}}, )
    return app
def create_app() ‑> flask.app.Flask
Expand source code
def create_app() -> Flask:
    return add_blueprints(init_app(Flask(__name__)))
def init_app(app: flask.app.Flask) ‑> flask.app.Flask
Expand source code
def init_app(app: Flask) -> Flask:
    @app.route('/')
    def index():
        """Empty page to check the deployment"""
        redirect_js = """
        <script>
        if (! window.location.pathname.toString().endsWith("/")) {
          document.location.href=window.location+"/"; 
        }
        </script>
        """
        if USE_GRAPHQL:
            return f"""
                {redirect_js}
                <body>
                <a href="haystack">Haystack API</a><br />
                <a href="graphql">Haystack GraphQL API</a><br />
                </body>
                """
        return f"""
            {redirect_js}
            <body>
            <a href="haystack">Haystack API</a><br />
            </body>
            """

    @app.route('/favicon.ico')
    def favicon():
        """Return the favorite icon"""
        return send_from_directory(os.path.join(app.root_path, 'static'),
                                   'favicon.ico', mimetype='image/vnd.microsoft.icon')

    app.logger.setLevel(_log_level)  # pylint: disable=no-member
    return app
def start_shaystack(host: str, port: int, app: flask.app.Flask) ‑> int

Stack a flask server. The command line must set the host and port.

Args

app
Flask app instance
host
Network to listen (0.0.0.0 to accept call from all network)
port
Port to listen

Envs

HAYSTACK_PROVIDER: to select a provider (shaystack.providers.db) HAYSTACK_DB: the URL to select the backend with the ontology

Expand source code
def start_shaystack(host: str, port: int, app: Flask) -> int:
    """Stack a flask server. The command line must set the host and port.

    Args:

        app: Flask app instance
        host: Network to listen (0.0.0.0 to accept call from all network)
        port: Port to listen

    Envs:

        HAYSTACK_PROVIDER: to select a provider (shaystack.providers.db)
        HAYSTACK_DB: the URL to select the backend with the ontology
    """
    debug = (os.environ.get("FLASK_DEBUG", "0") == "1")
    app.run(host=host,
            port=port,
            debug=debug)
    return 0