diff --git a/examples/petstore-access-control/app.py b/examples/petstore-access-control/app.py index 9d250aad..223feb6d 100644 --- a/examples/petstore-access-control/app.py +++ b/examples/petstore-access-control/app.py @@ -7,4 +7,4 @@ config_file="config.yaml" ) app = foca.create_app() - app.run() + app.run(port=app.app.config.get('port'), host=app.app.config.get('host')) diff --git a/examples/petstore-access-control/petstore-access-control.yaml b/examples/petstore-access-control/petstore-access-control.yaml index 3136a93d..74d54975 100644 --- a/examples/petstore-access-control/petstore-access-control.yaml +++ b/examples/petstore-access-control/petstore-access-control.yaml @@ -68,8 +68,8 @@ paths: content: application/json: schema: - x-body-name: pet $ref: '#/components/schemas/NewPet' + x-body-name: pet responses: '200': description: pet response diff --git a/examples/petstore/app.py b/examples/petstore/app.py index 9d250aad..223feb6d 100644 --- a/examples/petstore/app.py +++ b/examples/petstore/app.py @@ -7,4 +7,4 @@ config_file="config.yaml" ) app = foca.create_app() - app.run() + app.run(port=app.app.config.get('port'), host=app.app.config.get('host')) diff --git a/examples/petstore/petstore.yaml b/examples/petstore/petstore.yaml index 2109d653..692053c3 100644 --- a/examples/petstore/petstore.yaml +++ b/examples/petstore/petstore.yaml @@ -56,8 +56,8 @@ paths: content: application/json: schema: - x-body-name: pet $ref: '#/components/schemas/NewPet' + x-body-name: pet responses: '200': description: pet response diff --git a/foca/api/register_openapi.py b/foca/api/register_openapi.py index 40d865ef..891a0b0d 100644 --- a/foca/api/register_openapi.py +++ b/foca/api/register_openapi.py @@ -4,7 +4,7 @@ from pathlib import Path from typing import Dict, List -from connexion import App +import connexion from foca.models.config import SpecConfig from foca.config.config_parser import ConfigParser @@ -14,9 +14,9 @@ def register_openapi( - app: App, + app: connexion.FlaskApp, specs: List[SpecConfig], -) -> App: +) -> connexion.FlaskApp: """ Register OpenAPI specifications with Connexion application instance. diff --git a/foca/errors/exceptions.py b/foca/errors/exceptions.py index 0a62223e..14ba35da 100644 --- a/foca/errors/exceptions.py +++ b/foca/errors/exceptions.py @@ -5,7 +5,7 @@ from traceback import format_exception from typing import (Dict, List) -from connexion import App +import connexion from connexion.exceptions import ( ExtraParameterProblem, Forbidden, @@ -77,7 +77,7 @@ } -def register_exception_handler(app: App) -> App: +def register_exception_handler(app: connexion.FlaskApp) -> connexion.FlaskApp: """Register generic JSON problem handler with Connexion application instance. diff --git a/foca/factories/connexion_app.py b/foca/factories/connexion_app.py index b39b7f6c..10135052 100644 --- a/foca/factories/connexion_app.py +++ b/foca/factories/connexion_app.py @@ -3,16 +3,16 @@ from inspect import stack import logging from typing import Optional - -from connexion import App - +import connexion from foca.models.config import Config # Get logger instance logger = logging.getLogger(__name__) -def create_connexion_app(config: Optional[Config] = None) -> App: +def create_connexion_app( + config: Optional[Config] = None +) -> connexion.FlaskApp: """Create and configure Connexion application instance. Args: @@ -22,9 +22,9 @@ def create_connexion_app(config: Optional[Config] = None) -> App: Connexion application instance. """ # Instantiate Connexion app - app = App( + app = connexion.FlaskApp( __name__, - skip_error_handlers=True, + arguments=["port: 6000"] ) calling_module = ':'.join([stack()[1].filename, stack()[1].function]) @@ -41,9 +41,9 @@ def create_connexion_app(config: Optional[Config] = None) -> App: def __add_config_to_connexion_app( - app: App, + app: connexion.FlaskApp, config: Config, -) -> App: +) -> connexion.FlaskApp: """Replace default Flask and Connexion settings with FOCA configuration parameters. @@ -57,14 +57,13 @@ def __add_config_to_connexion_app( conf = config.server # replace Connexion app settings - app.host = conf.host - app.port = conf.port - app.debug = conf.debug + app.app.config["port"] = conf.port + app.app.config["host"] = conf.host # replace Flask app settings - app.app.config['DEBUG'] = conf.debug - app.app.config['ENV'] = conf.environment - app.app.config['TESTING'] = conf.testing + app.app.env = conf.environment + app.app.debug = conf.debug + app.app.testing = conf.testing logger.debug('Flask app settings:') for (key, value) in app.app.config.items(): diff --git a/foca/foca.py b/foca/foca.py index a249c896..bdfd7835 100644 --- a/foca/foca.py +++ b/foca/foca.py @@ -5,7 +5,7 @@ from typing import Optional from celery import Celery -from connexion import App +import connexion from foca.security.access_control.register_access_control import ( register_access_control, @@ -84,7 +84,7 @@ def __init__( else: logger.info("Default app configuration used.") - def create_app(self) -> App: + def create_app(self) -> connexion.FlaskApp: """Set up and initialize FOCA-based Connexion app. Returns: diff --git a/foca/security/access_control/register_access_control.py b/foca/security/access_control/register_access_control.py index fb76b669..bf055277 100644 --- a/foca/security/access_control/register_access_control.py +++ b/foca/security/access_control/register_access_control.py @@ -1,7 +1,7 @@ """Methods to manage permission management configuration""" import logging -from connexion import App +import connexion from connexion.exceptions import Forbidden from flask_authz import CasbinEnforcer from pkg_resources import resource_filename @@ -28,10 +28,10 @@ def register_access_control( - cnx_app: App, + cnx_app: connexion.FlaskApp, mongo_config: Optional[MongoConfig], access_control_config: AccessControlConfig -) -> App: +) -> connexion.FlaskApp: """Register access control configuration with flask app. Args: @@ -90,7 +90,7 @@ def register_access_control( def register_permission_specs( - app: App, + app: connexion.FlaskApp, access_control_config: AccessControlConfig ): """Register open api specs for permission management. @@ -137,10 +137,10 @@ def register_permission_specs( def register_casbin_enforcer( - app: App, + app: connexion.FlaskApp, access_control_config: AccessControlConfig, mongo_config: MongoConfig -) -> App: +) -> connexion.FlaskApp: """Method to add casbin permission enforcer. Args: @@ -191,7 +191,7 @@ def check_permissions( """ def _decorator_check_permissions(fn): - """User access decorator. Used to facilitate optional decorator arguments. + """User access decorator. Used to facilitate optional decorator arguments. # noqa Args: fn: The function to be decorated. diff --git a/foca/utils/logging.py b/foca/utils/logging.py index 2a47aaa9..f0d650f2 100644 --- a/foca/utils/logging.py +++ b/foca/utils/logging.py @@ -1,7 +1,7 @@ """Utility functions for logging.""" import logging -from connexion import request +from flask import request from functools import wraps from typing import (Callable, Optional) diff --git a/requirements.txt b/requirements.txt index 66a61dae..a045f1d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ addict==2.2.1 celery==5.2.2 -connexion>=2.11.2,<3.0.0 +connexion[flask] +connexion[uvicorn] cryptography==41.0.3 Flask==2.2.5 flask-authz==2.5.1 diff --git a/tests/api/test_register_openapi.py b/tests/api/test_register_openapi.py index 546f4250..75bd58f9 100644 --- a/tests/api/test_register_openapi.py +++ b/tests/api/test_register_openapi.py @@ -5,7 +5,7 @@ from copy import deepcopy from pathlib import Path -from connexion import App +import connexion from connexion.exceptions import InvalidSpecification import pytest from yaml import YAMLError @@ -80,54 +80,54 @@ class TestRegisterOpenAPI: def test_openapi_2_yaml(self): """Successfully register OpenAPI 2 YAML specs with Connexion app.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_2)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_3_yaml(self): """Successfully register OpenAPI 3 YAML specs with Connexion app.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_3)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_2_json(self): """Successfully register OpenAPI 2 JSON specs with Connexion app.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_2_JSON)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_2_json_and_3_yaml(self): """Successfully register both OpenAPI2 JSON and OpenAPI3 YAML specs with Connexion app. """ - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [ SpecConfig(**SPEC_CONFIG_2_JSON), SpecConfig(**SPEC_CONFIG_3), ] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_2_invalid(self): """Registration failing because of invalid OpenAPI 2 spec file.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(path=PATH_SPECS_INVALID_YAML)] with pytest.raises(InvalidSpecification): register_openapi(app=app, specs=spec_configs) def test_openapi_2_json_invalid(self): """Registration failing because of invalid JSON spec file.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(path=PATH_SPECS_INVALID_JSON)] with pytest.raises(ValueError): register_openapi(app=app, specs=spec_configs) def test_openapi_not_found(self): """Registration failing because spec file is unavailable.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(path=PATH_NOT_FOUND)] with pytest.raises(OSError): register_openapi(app=app, specs=spec_configs) @@ -136,34 +136,34 @@ def test_openapi_2_list(self): """Successfully register OpenAPI 2 JSON specs with Connexion app; specs provided as list. """ - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_2_LIST)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_2_fragments(self): """Successfully register OpenAPI 2 JSON specs with Connexion app; specs provided as multiple fragments. """ - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_2_MULTI)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_2_yaml_no_auth(self): """Successfully register OpenAPI 2 YAML specs with Connexion app; no security definitions/fields. """ - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_2_DISABLE_AUTH)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) def test_openapi_3_yaml_no_auth(self): """Successfully register OpenAPI 3 YAML specs with Connexion app; no security schemes/fields. """ - app = App(__name__) + app = connexion.FlaskApp(__name__) spec_configs = [SpecConfig(**SPEC_CONFIG_3_DISABLE_AUTH)] res = register_openapi(app=app, specs=spec_configs) - assert isinstance(res, App) + assert isinstance(res, connexion.FlaskApp) diff --git a/tests/database/test_register_mongodb.py b/tests/database/test_register_mongodb.py index e4f340ef..4efe6fab 100644 --- a/tests/database/test_register_mongodb.py +++ b/tests/database/test_register_mongodb.py @@ -10,7 +10,7 @@ from foca.models.config import MongoConfig MONGO_DICT_MIN = { - 'host': 'mongodb', + 'host': '127.0.0.1', 'port': 27017, } DB_DICT_NO_COLL = { diff --git a/tests/errors/test_errors.py b/tests/errors/test_errors.py index 93eb91dd..a1e9247d 100644 --- a/tests/errors/test_errors.py +++ b/tests/errors/test_errors.py @@ -6,7 +6,7 @@ import json from flask import (Flask, Response) -from connexion import App +import connexion import pytest from foca.errors.exceptions import ( @@ -52,9 +52,9 @@ class UnknownException(Exception): def test_register_exception_handler(): """Test exception handler registration with Connexion app.""" - app = App(__name__) + app = connexion.FlaskApp(__name__) ret = register_exception_handler(app) - assert isinstance(ret, App) + assert isinstance(ret, connexion.FlaskApp) def test__exc_to_str(): diff --git a/tests/factories/test_connexion_app.py b/tests/factories/test_connexion_app.py index 7da4b787..9c127282 100644 --- a/tests/factories/test_connexion_app.py +++ b/tests/factories/test_connexion_app.py @@ -1,6 +1,6 @@ """Tests for foca.factories.connexion_app.""" -from connexion import App +import connexion from foca.models.config import Config from foca.factories.connexion_app import ( @@ -22,19 +22,19 @@ def test_add_config_to_connexion_app(): """Test if app config is updated.""" - cnx_app = App(__name__) + cnx_app = connexion.FlaskApp(__name__) cnx_app = __add_config_to_connexion_app(cnx_app, CONFIG) - assert isinstance(cnx_app, App) + assert isinstance(cnx_app, connexion.FlaskApp) assert cnx_app.app.config.foca == CONFIG def test_create_connexion_app_without_config(): """Test Connexion app creation without config.""" cnx_app = create_connexion_app() - assert isinstance(cnx_app, App) + assert isinstance(cnx_app, connexion.FlaskApp) def test_create_connexion_app_with_config(): """Test Connexion app creation with config.""" cnx_app = create_connexion_app(CONFIG) - assert isinstance(cnx_app, App) + assert isinstance(cnx_app, connexion.FlaskApp) diff --git a/tests/test_foca.py b/tests/test_foca.py index 2ba7d186..ce6771c9 100644 --- a/tests/test_foca.py +++ b/tests/test_foca.py @@ -5,7 +5,7 @@ import shutil from celery import Celery -from connexion import App +import connexion from pydantic import ValidationError from pymongo.collection import Collection from pymongo.database import Database @@ -82,14 +82,14 @@ def test_foca_create_app_output_defaults(): """Ensure a Connexion app instance is returned; defaults only.""" foca = Foca() app = foca.create_app() - assert isinstance(app, App) + assert isinstance(app, connexion.FlaskApp) def test_foca_create_app_jobs(): """Ensure a Connexion app instance is returned; valid 'jobs' field.""" foca = Foca(config_file=JOBS_CONF) app = foca.create_app() - assert isinstance(app, App) + assert isinstance(app, connexion.FlaskApp) def test_foca_create_app_api(tmpdir): @@ -102,7 +102,7 @@ def test_foca_create_app_api(tmpdir): ) foca = Foca(config_file=temp_file) app = foca.create_app() - assert isinstance(app, App) + assert isinstance(app, connexion.FlaskApp) def test_foca_db(): @@ -113,7 +113,7 @@ def test_foca_db(): my_coll = my_db.collections["my-col-1"] assert isinstance(my_db.client, Database) assert isinstance(my_coll.client, Collection) - assert isinstance(app, App) + assert isinstance(app, connexion.FlaskApp) def test_foca_cors_config_flag_enabled(): @@ -145,7 +145,7 @@ def test_foca_valid_access_control(): my_coll = my_db.collections["test_collection"] assert isinstance(my_db.client, Database) assert isinstance(my_coll.client, Collection) - assert isinstance(app, App) + assert isinstance(app, connexion.FlaskApp) def test_foca_create_celery_app():