Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: add support for Connexion 3+ #204

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/petstore-access-control/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'))
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/petstore/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'))
2 changes: 1 addition & 1 deletion examples/petstore/petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions foca/api/register_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions foca/errors/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.

Expand Down
27 changes: 13 additions & 14 deletions foca/factories/connexion_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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])
Expand All @@ -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.

Expand All @@ -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():
Expand Down
4 changes: 2 additions & 2 deletions foca/foca.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down
14 changes: 7 additions & 7 deletions foca/security/access_control/register_access_control.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion foca/utils/logging.py
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down
40 changes: 20 additions & 20 deletions tests/api/test_register_openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
2 changes: 1 addition & 1 deletion tests/database/test_register_mongodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
6 changes: 3 additions & 3 deletions tests/errors/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import json

from flask import (Flask, Response)
from connexion import App
import connexion
import pytest

from foca.errors.exceptions import (
Expand Down Expand Up @@ -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():
Expand Down
Loading
Loading