spec-first / connexion

Connexion is a modern Python web framework that makes spec-first and api-first development easy.
https://connexion.readthedocs.io/en/latest/
Apache License 2.0
4.48k stars 761 forks source link

Flask-Migrate cant find Flask application #1863

Open Elthas17 opened 8 months ago

Elthas17 commented 8 months ago

Description

When i migrated to Connexion for my flask api, using the flask factory pattern, i adapted my create_app() to implement the FlaskApp from Connexion. The api runs fine, including the swagger ui.

But when i try to use flask-migrate it cant find the flask 'app' anymore.

I think it has something to do The create_app return. When i return the connexion FlaskApp , the application works and the swagger ui works. but Flask-Migrate cant find the 'app' and returns the error

Error: Failed to find Flask application or factory in module 'wsgi'. Use 'wsgi:name' to specify one.

When i return FlaskApp.app instead, Flask-Migrate does 'work' (migration script creator doesnt find any of the models so it wants to drop them all) , but the api / swagger ui does not work anymore.

Expected behaviour

Both connexion/swagger and flask-migrate work as intended

Actual behaviour

Flask-Migrate functionality broken

Steps to reproduce

My wsgi.py

from application import create_app
import os
from dotenv import load_dotenv
import socket

load_dotenv()
env = os.environ.get('ENV')
print('-------------------------------------------------------------')
print('The environment is {e}'.format(e=env))
print('-------------------------------------------------------------')

if not env:
    raise Exception('ENV is not set')

app = create_app()

which calls my init .py

import os
from dotenv import load_dotenv
from connexion import FlaskApp
from connexion.middleware import MiddlewarePosition
from starlette.middleware.cors import CORSMiddleware
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from flask_caching import Cache

load_dotenv()
env = os.environ.get('ENV')

db = SQLAlchemy()
migrate = Migrate()
ma = Marshmallow()
cache = Cache()

def create_app():
    connexion_flask_app = FlaskApp(__name__)
    connexion_flask_app.add_middleware(
        CORSMiddleware,
        position=MiddlewarePosition.BEFORE_EXCEPTION,
        allow_origins=["*"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    connexion_flask_app.add_api("openapi.yaml")
    app = connexion_flask_app.app
    config_name = 'config.{e}Config'.format(e=env.capitalize())
    app.config.from_object(config_name)

    # Initialize Plugins
    db.init_app(app)
    migrate.init_app(app, db)

    ma.init_app(app)
    cache.init_app(app)

    return connexion_flask_app

running Flask-migrate in project root with flask db migrate -m "testing"

returns

Error: Failed to find Flask application or factory in module 'wsgi'. Use 'wsgi:name' to specify one.

Usage: flask [OPTIONS] COMMAND [ARGS]... Try 'flask --help' for help.

Error: No such command 'db'.

Additional info:

Output of the commands:

RobbeSneyders commented 7 months ago

Hi @Elthas17,

To run connexion, you need to target the connexion app (connexion_flask_app in your code). To run flask-migrate, you need to target the flask app (app or connexion_flask_app.app in your code).

You'll probably need to return both from your factory function, or target them explicitly.

I'm not familiar with flask-migrate, so not sure what the issue with the models is, but it might be because connexion only registers the apis/blueprints and routes on the application at startup. If you can demonstrate that this is indeed the underlying issue, we can expose this functionality via a method so you can manually trigger it before startup.

glhdavenport commented 4 months ago

@Elthas17, I am running into the same problem. Curious to know if you got it working.