gunicorn: Failed to find attribute 'app' in module - python

Hi I am trying to run,
gunicorn --bind localhost:8000 --worker-class sanic_gunicorn.Worker module:app
where I have following files
# ls
build
setup.py
dist
module
module.egg-info
venv
#cd module
#ls
__init__.py
__pycache__
__main__.py
app.py
content of __main__.py is as follows
from module.app import create_app_instance
if __name__ == '__main__':
app = create_app_instance()
app.run()
and content of app.py is
#some imports
def create_app_instance():
app = Sanic(name = "app_name")
.....
return app
I am using Sanic web framework and when I am running it's dev server as python -m module it works fine
python3 -m module
[2021-06-16 22:31:36 -0700] [80176] [INFO] Goin' Fast # http://127.0.0.1:8000
[2021-06-16 22:31:36 -0700] [80176] [INFO] Starting worker [80176]
can someone let me know what am I doing wrong ?

The simple answer is that there's no app exposed inside the module. You have the create_app_instance() method but this is not called.
I would suggest for you to refactor your code as follows. File structure would be:
./wsgi.py
./module/__init__.py
And the contents of those files as below:
.\wsgi.py
from module import create_app_instance
app = create_app_instance()
if __name__ == '__main__':
app.run()
.\module\__init__.py
# this is the contents of your current app.py
#some imports
def create_app_instance():
app = Sanic(name = "app_name")
.....
return app
and then the gunicorn line to start the server would be (please note the comment from The Brewmaster below):
gunicorn --bind localhost:8000 --worker-class sanic_gunicorn.Worker wsgi:app
What this does is it calls the exposed app instance inside wsgi.py. The __main__.py is not needed, and the code from your app.py has been moved to the __init__.py
I highly advise you to read through documentation/tutorials for Application Factory Pattern for Flask. The principle itself is the same as for Sanic, but there's more articles that describe the principle for Flask...

Related

How to deploy Python API on heroku ? No module named 'app' error

I'm a total beginner with heroku and API's but I needed to execute some python for a mobile app project.
Anyway I watched a ton of tutorial and looked for the doc on heroku website but my problem remains the same :
I push my project using $ git push heroku master but when loading the page where my API should appear I get an application error from heroku which tells to check the logs.
So in the logs I am facing the following error : << ModuleNotFoundError: No module named 'app' >>
I have this code :
app.py
import flask
app = flask.Flask(__name__)
#app.route('/')
def home():
return 'hello'
Procfile
web: gunicorn testdamien.wsgi
wsgi.py
from app import app
if __name__ == '__main__':
app.run()
I don't really know what's the use of the wsgi file, I saw some youtubers not using it and directly putting the app.run() in the app.py.
Also, I tried with the following Procfile :
web: gunicorn app:app
don't work either...
Thank you for reading me.
So in your app.py your application is not running. Edit the file as below:
import flask
app = flask.Flask(__name__)
#app.route('/')
def home():
return 'hello'
if __name__ == '__main__':
app.run(host='0.0.0.0')
in your Procfile you are specifying your entry-point the format is web: gunicorn your_module_name:your_application name In your case it will be:
web: gunicorn app:app
Should work fine

FastAPI throws an error (Error loading ASGI app. Could not import module "api")

I tried to run FastAPI using uvicorn webserver but it throws an error.
I run this command,
uvicorn api:app --reload --host 0.0.0.0
but there is an error in the terminal.
Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
Started reloader process [23445]
Error loading ASGI app. Could not import module "api".
Stopping reloader process [23445]
TL;DR
Add the directory name in front of your filename
uvicorn src.main:app
or cd into that directory
cd src
uvicorn main:app
Long Answer
It happens because you are not in the same folder with your FastAPI app instance more specifically:
Let's say i have an app-tree like this;
my_fastapi_app/
├── app.yaml
├── docker-compose.yml
├── src
│   └── main.py
└── tests
├── test_xx.py
└── test_yy.py
$ pwd # Present Working Directory
/home/yagiz/Desktop/my_fastapi_app
I'm not inside the same folder with my app instance, so if I try to run my app with uvicorn I'll get an error like yours
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [40645] using statreload
ERROR: Error loading ASGI app. Could not import module "main".
The answer is so simple, add the folder name in front of your filename
uvicorn src.main:app --reload
or you can change your working directory
cd src
Now i'm inside of the folder with my app instance
src
└── main.py
Run your uvicorn again
$ uvicorn main:app --reload
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [40726] using statreload
INFO: Started server process [40728]
INFO: Waiting for application startup.
INFO: Application startup complete.
One reason this might be happening is that you are using:
uvicorn src/main:app --reload
instead of the correct syntax:
uvicorn src.main:app --reload
Notice the . instead of the /
Currently auto-completion in the terminal suggests the wrong format.
That's assuming that:
(1) your structure is something like this:
project_folder/
├── some_folder
├── src
│ └── main.py
└── tests
├── test_xx.py
└── test_yy.py
(2) your FastAPI() object is indeed assigned to an object named app in main.py:
app = FastAPI()
(3) you are running the uvicorn command from the project_folder, e.g.:
(venv) <username>#<pcname>:~/PycharmProjects/project_folder$ uvicorn src.main:app --reload
I had the same problem and solved it adding package name before main, in your case trying:
uvicorn src.main:app --reload
may solve the problem
This worked for me look at the docs for fastAPI. I am very thankful I ran accross that as the Python script needs to be named main.py not app.py
The command uvicorn main:app refers to:
main: the file main.py (the Python "module").
app: the object created inside of main.py with the line app = FastAPI()
--reload: make the server restart after code changes. Only use for
development.
It seems it is important that you name your file main.py otherwise it won't work.
Edit: Actually I was running Jupyter Notebook on port 8888 so that port was already occupied. If you have to run Jupyter notebook, run it after running the API server, the notebook will automatically run on 8889.
Alternatively, you can run the API server on a different port.
Hit the Save button in VS Code etc because sometimes it will throw this error if you have not saved the file. Happened to me.
Another reason for this error: there is a circular reference between files.
Example:
main.py:
from tools import validator
# ...
class GlobalException(Exception):
# ...
/tools/validator.py:
from main import GlobalException
Use this folder structure and configuration where main is in parent directory
launch.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: FastAPI",
"type": "python",
"request": "launch",
"module": "uvicorn",
"args": [
"main:app"
],
"jinja": true
}
]
}
main.py
from fastapi import FastAPI
app = FastAPI(
title="test",
description="test",
version="0.0.1",
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host="0.0.0.0",
reload=True,
port=3001,
)
Also another reason for this error:
There's already a file named exactly like your running folder, then it will make a conflict to the system.
Example you have a file inside a folder named test_app/main.py, then you should run uvicorn test_app.main:app --reload to run the app.
But, if you have a file named test_app.py (which is the same name as the folder above), it will throw the error when you run the app.
So the solution is to rename the folder or rename the file so they won't be conflict to each other.
Step-1 make sure your main file is located in the same directory of your terminal/command prompt, use ls command
(virtual-env) shayon#shayon-X556UQK:~/Documents/python-fast-api$ ls
main.py __pycache__ README.md requirements.txt virtual-env
Step-2 check the directory of your terminal using pwd command
(virtual-env) shayon#shayon-X556UQK:~/Documents/python-fast-api$ pwd
/home/shayon/Documents/python-fast-api
Step-3 check the name of your object - here app is the object of FastAPI so we need to use the command uvicorn main:app --reload, if you keep the object name app1 you need to run uvicorn main:app1 --reload
(virtual-env) shayon#shayon-X556UQK:~/Documents/python-fast-api$ cat main.py
main.py
from fastapi import FastAPI
app = FastAPI()
#app.get("/")
def index():
return {"Hello": "World"}
Step-4 In my case, I made a mistake making command of uvicorn main.py:app --reload and this was the reason for my error. The command should be uvicorn main:app --reload (without dot py extension)
Hope this help - Enjoy :)
If you are using Pycharm , the reason could be the source directory not being set correctly. For example, I was trying to configure Python remote debugger using docker-compose and my folder structure was like this:
my_app_name
├── docker-compose.yml
├── src
│ └── main.py
└── tests
├── test_file1.py
└── test_file2.py
I had the src folder inside the root folder, which contained the main.py file. In PyCharm project settings, by default your source folder is set to root.But if you have a nested structure like the case above, you have to go to Preferences->Project->Project Structure->Sources and add your src folder under Source Folders.
I also encountered the same issue,
being a total beginner to FastAPI, the solution given by Yagiz Degirmenci
helped to come up with a simple idea for beginners like me, i.e
cd directory of code
uvicorn fast-api:main --reload
PS. fast-api is the name of my file (i.e fast-api.py)
I fixed this by using the following in my main:
import uvicorn
app = FastAPI()
#app.get("/")
def index():
return {"index": "root"}
if __name__ == '__main__':
uvicorn.run(f"{Path(__file__).stem}:app", host="127.0.0.1", port=8888, reload=True)
and then from the terminal, I typed uvicorn main:app --reload as my main.py is in my root folder.
don't give the same name for your python file like uvicorn.py,Folder same name, package name

Docker+Gunicorn+Flask, I don't understand why my setup is not working

I'm trying to build a simple application with flask and I've decided to also use gunicorn and docker.
At the moment I have this configuration:
> app
> myapp
__init__.py
index.html
docker-compose.yml
Dockerfile
My docker-compose.yml:
version: '2'
services:
web:
build: .
volumes:
- .:/app
command: /usr/local/bin/gunicorn -b :8000 myapp:app
working_dir: /app
My __init__.py:
import os
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def home():
return render_template('index.html')
if __name__ == '__main__':
app.run()
This minimal configuration works and I'm able to access my application and get my index page.
What I don't like is having my app created inside the __init__.py so I would like to move the app creation inside an app.py file.
The new structure will be:
> app
> myapp
__init__.py
app.py
index.html
docker-compose.yml
Dockerfile
app.py will have the content of the old __init__.py file and the new __init__.py file would be empty.
This doesn't work. I get an error
Failed to find application: 'myapp'
and I don't understand why.
Any idea about this?
In the first configuration, your Flask app was located directly in the package myapp; after you moved it, it is in the module myapp.app.
Gunicorn expects the app to be specified as module_name:variable_name, somewhat like from module_name import variable_name.
Option one: specify the correct module path:
/usr/local/bin/gunicorn -b :8000 myapp.app:app
Option two: add the app back to myapp. In myapp/__init__.py, add
from .app import app
Note that if the variable and the module share the name, the module will be overshadowed (not a good thing, although not a critical either).

Flask/uWSGI throws error unable to load app 0 (mountpoint='')

Im trying to run (just for testing purposes):
uwsgi --socket 0.0.0.0:8000 --protocol=http -w wsgi_prod
from a dir with:
home.py
home.pyc
wsgi_prod.py
wsgi_prod.pyc
my wsgi_prod.py has:
from home import app
if __name__ == "__main__":
app.run()
home.py has:
from flask import Flask, render_template
from jinja2 import Template
app = Flask(__name__, static_folder='static')
#app.route('/')
def home():
print('Hello world')
if __name__ == '__main__':
app.run(host='0.0.0.0')
When I run it, it throws:
unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI worker 1 (and the only)
What am I doing wrong? Why cant it see my app?
Thank you!
Well, I hope this helps someone out someday. Digital Ocean offers a great article to setup your flask/uwsgi, but offers the wrong command for this.
Use this instead:
uwsgi --socket 0.0.0.0:8000 --protocol=http -w wsgi_prod:app
and use this link

Auto reloading Flask app when source code changes

I know for a fact that Flask, in debug mode, will detect changes to .py source code files and will reload them when new requests come in.
I used to see this in my app all the time. Change a little text in an #app.route decoration section in my views.py file, and I could see the changes in the browser upon refresh.
But all of a sudden (can't remember what changed), this doesn't seem to work anymore.
Q: Where am I going wrong?
I am running on a OSX 10.9 system with a VENV setup using Python 2.7. I use foreman start in my project root to start it up.
App structure is like this:
[Project Root]
+-[app]
| +-__init__.py
| +- views.py
| +- ...some other files...
+-[venv]
+- config.py
+- Procfile
+- run.py
The files look like this:
# Procfile
web: gunicorn --log-level=DEBUG run:app
# config.py
contains some app specific configuration information.
# run.py
from app import app
if __name__ == "__main__":
app.run(debug = True, port = 5000)
# __init__.py
from flask import Flask
from flask.ext.login import LoginManager
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.mail import Mail
import os
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
#mail sending
mail = Mail(app)
lm = LoginManager()
lm.init_app(app)
lm.session_protection = "strong"
from app import views, models
# app/views.py
#app.route('/start-scep')
def start_scep():
startMessage = '''\
<html>
<header>
<style>
body { margin:40px 40px;font-family:Helvetica;}
h1 { font-size:40px; }
p { font-size:30px; }
a { text-decoration:none; }
</style>
</header>
<p>Some text</p>
</body>
</html>\
'''
response = make_response(startMessage)
response.headers['Content-Type'] = "text/html"
print response.headers
return response
The issue here, as stated in other answers, is that it looks like you moved from python run.py to foreman start, or you changed your Procfile from
# Procfile
web: python run.py
to
# Procfile
web: gunicorn --log-level=DEBUG run:app
When you run foreman start, it simply runs the commands that you've specified in the Procfile. (I'm going to guess you're working with Heroku, but even if not, this is nice because it will mimic what's going to run on your server/Heroku dyno/whatever.)
So now, when you run gunicorn --log-level=DEBUG run:app (via foreman start) you are now running your application with gunicorn rather than the built in webserver that comes with Flask. The run:app argument tells gunicorn to look in run.py for a Flask instance named app, import it, and run it. This is where it get's fun: since the run.py is being imported, __name__ == '__main__' is False (see more on that here), and so app.run(debug = True, port = 5000) is never called.
This is what you want (at least in a setting that's available publicly) because the webserver that's built into Flask that's used when app.run() is called has some pretty serious security vulnerabilities. The --log-level=DEBUG may also be a bit deceiving since it uses the word "DEBUG" but it's only telling gunicorn which logging statements to print and which to ignore (check out the Python docs on logging.)
The solution is to run python run.py when running the app locally and working/debugging on it, and only run foreman start when you want to mimic a production environment. Also, since gunicorn only needs to import the app object, you could remove some ambiguity and change your Procfile to
# Procfile
web: gunicorn --log-level=DEBUG app:app
You could also look into Flask Script which has a built in command python manage.py runserver that runs the built in Flask webserver in debug mode.
The solution was to stop using foreman start as stated in the comments and directly execute python run.py.
This way, the app.run method with the debug=True and use_reloader=True configuration parameters take effect.
Sample Application where app is our application and this application had been saved in the file start.py:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hallo():
return 'Hello World, this is really cool... that rocks... LOL'
now we start the application from the shell with the flag --reload
gunicorn -w 1 -b 127.0.0.1:3032 start:app --reload
and gunicorn reloads the application at the moment the file has changed automaticly. No need to change anything at all.
if you'd love to run this application in the background add the flag -D
gunicorn -D -w 1 -b 127.0.0.1:3032 start:app --reload
-D Demon mode
-w number of workers
-b address and port
start (start.py) :app - application
--reload gunicorns file monitoring
Look at the settings file:
http://docs.gunicorn.org/en/latest/settings.html
all options and flags are mentioned there. Have fun!

Categories