def test_default_specs(app, cli_runner): swagger = Swagger(app) result = cli_runner.invoke(generate_api_schema) assert result.exit_code == 0 spec = json.loads(result.output) assert spec == swagger.get_apispecs(Swagger.DEFAULT_ENDPOINT)
def test_get_apispecs_with_invalid_endpoint(app): swagger = Swagger(app) with app.app_context(): with pytest.raises(RuntimeError) as e: bad_endpoint = "Bad endpoint" swagger.get_apispecs(bad_endpoint) assert bad_endpoint in e
def test_custom_specs(app, cli_runner): endpoint = "custom_endpoint" config = dict(Swagger.DEFAULT_CONFIG) config["specs"][0]["endpoint"] = endpoint swagger = Swagger(app, config=config) result = cli_runner.invoke(generate_api_schema, ["-e", endpoint]) assert result.exit_code == 0 spec = json.loads(result.output) assert spec == swagger.get_apispecs(endpoint)
def test_invalid_endpoint(app, cli_runner): endpoint = "custom_endpoint" config = dict(Swagger.DEFAULT_CONFIG) config["specs"][0]["endpoint"] = endpoint Swagger(app, config=config) result = cli_runner.invoke(generate_api_schema, ["-e", "other_endpoint"]) assert result.exit_code == 1 assert "other_endpoint" in result.stderr
def test_definitions_is_removed_for_openapi_3(app, cli_runner): app.config["SWAGGER"] = { "openapi": "3.0.3", } Swagger(app) result = cli_runner.invoke(generate_api_schema) assert result.exit_code == 0 assert "definitions" not in json.loads(result.output)
def test_init_config(monkeypatch): def __init__(self, config=None, merge=False): self._init_config(config, merge) monkeypatch.setattr(Swagger, "__init__", __init__) # # Unspecified config will be initialized to dict() t = Swagger(config=None, merge=False) assert t.config == Swagger.DEFAULT_CONFIG # Empty dict passed to arguments will be overriden with default_config empty_dict = dict() t = Swagger(config=empty_dict, merge=False) assert t.config == Swagger.DEFAULT_CONFIG assert t.config is not empty_dict # Config will be merged d = {"a": 0} t = Swagger(config=d, merge=False) assert t.config is d # Config will be overridden t = Swagger(config={"a": 0}, merge=False) assert t.config == {"a": 0} # Config will be merged t = Swagger(config={"a": 0}, merge=True) assert t.config.items() > {"a": 0}.items() assert all(t.config[k] == v for k, v in Swagger.DEFAULT_CONFIG.items()) # Config will be merged empty_dict = dict() t = Swagger(config=empty_dict, merge=True) assert t.config == Swagger.DEFAULT_CONFIG # keys in DEFAULT_CONFIG will be overridden d = { "specs": [{ "endpoint": "swagger", "route": "/characteristics/swagger.json", "rule_filter": lambda rule: True, # all in "model_filter": lambda tag: True, # all in }], } t = Swagger(config=d, merge=True) assert all(t.config[k] == v for k, v in d.items()) assert t.config["specs"] == d["specs"]
def create_app(): """create flask app""" app = Flask(__name__) app.config.from_pyfile("config.py", silent=True) logger.warning("database: " + app.config["MPCONTRIBS_DB"]) app.config["USTS"] = URLSafeTimedSerializer(app.secret_key) app.jinja_env.globals["get_resource_as_string"] = get_resource_as_string app.jinja_env.lstrip_blocks = True app.jinja_env.trim_blocks = True if app.config.get("DEBUG"): from flask_cors import CORS CORS(app) # enable for development (allow localhost) Compress(app) Logging(app) Marshmallow(app) MongoEngine(app) Swagger(app, template=app.config.get("TEMPLATE")) # NOTE: hard-code to avoid pre-generating for new deployment # collections = get_collections(db) collections = [ "projects", "contributions", "tables", "structures", "notebooks", ] for collection in collections: module_path = ".".join(["mpcontribs", "api", collection, "views"]) try: module = import_module(module_path) except ModuleNotFoundError as ex: logger.warning(f"API module {module_path}: {ex}") continue try: blueprint = getattr(module, collection) app.register_blueprint(blueprint, url_prefix="/" + collection) klass = getattr(module, collection.capitalize() + "View") register_class(app, klass, name=collection) logger.warning(f"{collection} registered") except AttributeError as ex: logger.warning( f"Failed to register {module_path}: {collection} {ex}") # TODO discover user-contributed views automatically # only load for main deployment if os.environ.get("API_PORT", "5000") == "5000": collection = "redox_thermo_csp" module_path = ".".join(["mpcontribs", "api", collection, "views"]) try: module = import_module(module_path) blueprint = getattr(module, collection) app.register_blueprint(blueprint, url_prefix="/" + collection) logger.warning(f"{collection} registered") except ModuleNotFoundError as ex: logger.warning(f"API module {module_path}: {ex}") app.register_blueprint(sse, url_prefix="/stream") # TODO add healthcheck view/url logger.warning("app created.") return app
# Initialize core objects app = Flask(__name__) app.config.from_object("config") cache = Cache(app) cors = CORS(app) db = SQLAlchemy(app) jwt = JWTManager(app) limiter = Limiter( app, key_func=get_remote_address, default_limits=["100 per minute", "5 per second"], ) mail = Mail(app) swagger = Swagger(app) storage = Minio(app) rq = RQ(app) # -- Handler from app.handlers import (http_handler, jwt_handler, log_handler) # Comment above code when change database systems if not os.path.exists("db.sqlite"): db.create_all() # -- Controllers from app.controllers import (auth_controller, file_controller, homepage_controller, mail_controller, user_controller)
def test_get_apispecs_with_valid_endpoint(app): swagger = Swagger(app) with app.app_context(): assert swagger.get_apispecs(Swagger.DEFAULT_ENDPOINT)
def create_app(): """create flask app""" app = Flask(__name__) app.config.from_pyfile("config.py", silent=True) app.config["USTS"] = URLSafeTimedSerializer(app.secret_key) app.jinja_env.globals["get_resource_as_string"] = get_resource_as_string app.jinja_env.lstrip_blocks = True app.jinja_env.trim_blocks = True app.config["TEMPLATE"]["schemes"] = ["http"] if app.debug else ["https"] MPCONTRIBS_API_HOST = os.environ["MPCONTRIBS_API_HOST"] logger.info("database: " + app.config["MPCONTRIBS_DB"]) if app.debug: from flask_cors import CORS CORS(app) # enable for development (allow localhost) Compress(app) Marshmallow(app) MongoEngine(app) Swagger(app, template=app.config.get("TEMPLATE")) setattr(app, "kernels", get_kernels()) # NOTE: hard-code to avoid pre-generating for new deployment # collections = get_collections(db) collections = [ "projects", "contributions", "tables", "attachments", "structures", "notebooks", ] for collection in collections: module_path = ".".join(["mpcontribs", "api", collection, "views"]) try: module = import_module(module_path) except ModuleNotFoundError as ex: logger.error(f"API module {module_path}: {ex}") continue try: blueprint = getattr(module, collection) app.register_blueprint(blueprint, url_prefix="/" + collection) klass = getattr(module, collection.capitalize() + "View") register_class(app, klass, name=collection) logger.info(f"{collection} registered") except AttributeError as ex: logger.error( f"Failed to register {module_path}: {collection} {ex}") if app.kernels: from mpcontribs.api.notebooks.views import rq, make rq.init_app(app) if is_gunicorn: setattr(app, "cron_job_id", f"auto-notebooks-build_{MPCONTRIBS_API_HOST}") make.cron('*/3 * * * *', app.cron_job_id) logger.info(f"CRONJOB {app.cron_job_id} added.") def healthcheck(): # TODO run mpcontribs-api in next-gen task on different port so this won't be needed # spams logs with expected 500 errors if not app.debug and not app.kernels: return "KERNEL GATEWAY NOT AVAILABLE", 500 return "OK" if is_gunicorn: app.register_blueprint(sse, url_prefix="/stream") app.add_url_rule("/healthcheck", view_func=healthcheck) #app.register_blueprint(rq_dashboard.blueprint, url_prefix="/rq") #dashboard.config.init_from(file="dashboard.cfg") #dashboard.config.version = app.config["VERSION"] #dashboard.config.table_prefix = f"fmd_{MPCONTRIBS_API_HOST}" #db_password = os.environ["POSTGRES_DB_PASSWORD"] #db_host = os.environ["POSTGRES_DB_HOST"] #dashboard.config.database_name = f"postgresql://*****:*****@{db_host}/kong" #dashboard.bind(app) logger.info("app created.") return app