18

This is maybe a Python noob question, but after having spent a whole day searching, I couldn't find a solution.

I created a simple Flask application, here is an extract of the python_pgfutter_importer/app.py:

import os

from flask import Flask, Blueprint

from python_pgfutter_importer import settings
from python_pgfutter_importer.api.importer.business import import_csv
from python_pgfutter_importer.api.importer.endpoints.csv import ns as csv_importer_namespace
from python_pgfutter_importer.api.restplus import api

app = Flask(__name__)


def initialize_app(flask_app):
    blueprint = Blueprint('api', __name__, url_prefix='/api')
    api.init_app(blueprint)
    api.add_namespace(csv_importer_namespace)
    flask_app.register_blueprint(blueprint)


def main():
    initialize_app(app)
    app.run(debug=settings.FLASK_DEBUG, use_reloader=settings.FLASK_USE_RELOADER)


if __name__ == "__main__":
    main()

Application is working well, I start it using this command:

python python_pgfutter_importer/app.py

Now I must host this application on a server, thus I have to use WSGI. Using all the tutorials I could find, I wrote this WSGI entry point (wsgi.py):

from python_pgfutter_importer import app as application

if __name__ == "__main__":
    application.main()

When starting Gunicorn, here is the CLI output:

$gunicorn -b 127.0.0.1:8000 wsgi:application               
[2018-11-12 09:15:48 +0100] [11782] [INFO] Starting gunicorn 19.9.0
[2018-11-12 09:15:48 +0100] [11782] [INFO] Listening at: http://127.0.0.1:8000 (11782)
[2018-11-12 09:15:48 +0100] [11782] [INFO] Using worker: sync
[2018-11-12 09:15:48 +0100] [11785] [INFO] Booting worker with pid: 11785
Application object must be callable.
[2018-11-12 09:15:48 +0100] [11782] [INFO] Shutting down: Master
[2018-11-12 09:15:48 +0100] [11782] [INFO] Reason: App failed to load.

It seems the problem is: Application object must be callable.

That doesn't make any sense, since the application is Flask and is of course callable.

What can I be missing?

Thanks

frinux
  • 2,052
  • 6
  • 26
  • 47

1 Answers1

19

Given your path is python_pgfutter_importer/app.py, it looks like your import in wsgi.py is off:

from python_pgfutter_importer import app as application

This makes application a module object, what you need is an app:

from python_pgfutter_importer.app import app as application

Alternatively, you could probably do away with wsgi.py if you change wsgi:application in Gunicorn's command line to python_pgfutter_importer.app:app. Docs.

Norrius
  • 7,558
  • 5
  • 40
  • 49
  • Thanks it seems better, Gunicorn starts. But requests are not answered. I've put a log at the beginning of app.py:main() method, and it is never reached, it seems the main() is never called – frinux Nov 12 '18 at 09:10
  • @frinux It is never called because it is guarded by `if __name__ == '__main__'`. But then if you have Gunicorn, why do you need to run it manually? – Norrius Nov 12 '18 at 09:13
  • the main() method contains the application initialization (scheduler creation, app configuration, and finally app.run() method) Am I wrong to put this code here? – frinux Nov 12 '18 at 09:19
  • @frinux You could call `initialize_app()` at the top level, for example see answers to this question: https://stackoverflow.com/q/22260127/1983772 – Norrius Nov 12 '18 at 09:50
  • Init code can indeed be put at the first level in app.py, just before main() method. Thanks @Norrius! – frinux Nov 12 '18 at 10:19