Using flask-restful, i can not import the object mongo = PyMongo() from the file app/__init__.py into app/common/db.py.
My folder structure looks like this:
myproject/
run.py
app/
__init__.py
config.py
common/
__init__.py
db.py
auth/
__init__.py
resources.py
app/__init__.py contains:
from flask import Flask, Blueprint
from flask_pymongo import PyMongo
from flask_restful import Api
from app.config import Config
from app.auth.resources import Foo
mongo = PyMongo()
bp_auth = Blueprint('auth', __name__)
api_auth = Api(bp_auth)
api_auth.add_resource(Foo, '/foo/<string:name>')
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
mongo.init_app(app)
app.register_blueprint(bp_auth)
return app
app/common/db.py contains:
from app import mongo
the application itself is run from the root via run.py which contains:
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
Problem:
Running the application i get an ImportError:
from app import mongo
ImportError: cannot import name 'mongo'
Why this is not working?
Thanks for your help!
EDIT:
Full Traceback:
Traceback (most recent call last):
File "run.py", line 1, in <module>
from app import create_app
File "/home/bt/Dropbox/dev/flask/test_api/app/__init__.py", line 13, in <module>
from app.auth.resources import SignIn, Users, User, Foo
File "/home/bt/Dropbox/dev/flask/test_api/app/auth/resources.py", line 8, in <module>
from app.common.resources import AuthResource
File "/home/bt/Dropbox/dev/flask/test_api/app/common/resources.py", line 3, in <module>
from app.auth.decorators import token_required
File "/home/bt/Dropbox/dev/flask/test_api/app/auth/decorators.py", line 6, in <module>
from app.common.database import users
File "/home/bt/Dropbox/dev/flask/test_api/app/common/database.py", line 1, in <module>
from app import mongo
ImportError: cannot import name 'mongo'
As I suspected, this is a circular import problem.
You can track the closed loop of dependencies looking at the traceback:
app -> resources -> database -> app
This is a common mistake and not properly documented in Flask tutorials. As explained here by Lepture, you should avoid declaring db in the __init__.py
I always keep this one certain rule when writing modules and packages:
Don't backward import from root __init__.py.
How should you do it, then?
declare db in the proper module (db.py)
import it inside the application factory
I found myself reluctant towards this pattern, I thought those import statements didn't belong inside a function. But this is the way to go.
So, your files should look something alike:
app/common/db.py
from flask_pymongo import PyMongo
mongo = PyMongo
app/__init__.py
from flask import Flask
...
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
from app.common.db import mongo
mongo.init_app(app)
...
and when you need your database connection, i.e. in resources module, you should import it like
from app.common.db import mongo
Note: to avoid future problems, your blueprints should also be declared elsewhere and import on creation time. I really encourage you to read the post by Lepture to better understand this approach.
Related
The Following is my code hierarchy.
I am trying to create a package for my project, "UIGenerator" but it is giving me following error.
traceback (most recent call last):
File "run.py", line 1, in <module>
from UIGenerator import app
File "/Users/______/Desktop/UIGenerator/UIGenerator/__init__.py", line 2, in <module>
from site.routes import site
ModuleNotFoundError: No module named 'site.routes'; 'site' is not a package
Here is the code for run.py =>
from UIGenerator import app
#app.route('/')
def test_connection():
return "<h1>Connected<h1>"
if __name__ == '__main__':
app.run(debug=True)
There is nothing in site =>__init__.py file and in site=>routes.py, I have some sample code to test-
from flask import Blueprint
site = Blueprint('site', __name__)
#site.route('/site')
def site():
return "this is test for site package"
The following is my code for the UIGenerator's init.py file =>
from flask import Flask
from site.routes import site
def getApp():
app = Flask(__name__)
app.register_blueprint(site)
return app
app = getApp()
Can anyone give me any clue, please.
One way to fix this is to build a Python package with you files, like outlined here. This will be better in the long run if you want to scale this project up, and will allow you to declare things in init
That being said, I think you can get your setup working by moving this chunk of code
def getApp():
app = Flask(__name__)
app.register_blueprint(site)
return app
app = getApp()
to the run.py file for the time being.
So, here is what I found out from a different post. In my site=>routes, I declared a global blueprint with the name, site and later I created a site() function which somehow masked my site blueprint. If I just renamed the site method name, it works.
I got stuck on import error when running python manage.py db migrate for my Flask app. I tried a lot of combinations with import statements in traceback files (general, local).
Traceback (most recent call last):
File "src/manage.py", line 7, in <module>
from api import app, db
File "/api/src/api.py", line 6, in <module>
import auth.views
File "/api/src/auth/views.py", line 3, in <module>
import models
File "/api/src/models.py", line 2, in <module>
from api import app
ImportError: cannot import name 'app'
Any idea?
Can you try
import os
from flask import Flask
from flask_bcrypt import Bcrypt
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
app_settings = os.getenv(
'APP_SETTINGS',
'config.DevelopmentConfig'
)
app.config.from_object(app_settings)
bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
# Try by keeping the import here?
import auth.views
app.register_blueprint(auth.views.auth_blueprint)
Most probable reason for this issue would be that you are referring app Flask object in your auth.views and models even before you create the app object....
ImportError: cannot import name 'app'
so if you import the auth.views after your app creation, then the reference would work....
__init__.py are use to mark directories on disk as a Python package directories. lets say we have the files
py/src/__init__.py
py/src/user.py
and py is on your path, you can import the code in user.py as:
import src.module
or
from src import user
If we remove the __init__.py file, Python will no longer look for submodules inside that directory, so attempts to import the module will fail.
But on my app the __init__.py is not working.
__init__ .py
__all__ = ['models', 'common']
from src.models.user import User
from src.models.post import Post
from src.models.blog import Blog
When I run python app.py
errors:
Traceback (most recent call last):
File "src/app.py", line 5, in <module>
from src.models.user import User
ModuleNotFoundError: No module named 'src'
App.py file:
import os
import sys
from flask import Flask, render_template, request, session
from src.models.user import User
app = Flask(__name__) #'__main__'
#app.route('/') # 'OUrsite.com/api/'
# def hello world ot test the first api call
def hello_method():
return render_template('login.html')
#app.route('/login')
def login_user():
email = request.form['email']
password = request.form['password']
if User.login_valid(email, password):
User.login(email)
return render_template("profile.html", email=session['email'])
if __name__ == '__main__':
app.run(port = 9100)
Am I missing something?
There are two things to understand.
There is a difference in root directory of virtualenv and your system environment.
Virtualenv sets your project dir to it's root. But in case you are not using virtualenv, the root would be your system directory (at least, in my experience).
So, while creating __init__py, keep in mind that, if there is no virtualenv or you haven't imported anything, it can be empty.
simple __init_.py examples:
# in your __init__.py
from file import File
# now import File from package
from package import File
My __init__.py:
import src
from src import *
from .models.user import User
from .models.post import Post
from .models.blog import Blog
And when you import in app.py or src/models/user.py which is in a same directory & subdirectory, you shall not include src:
from models.user import User
from common.database import Database
You didn't import src first.
import src
__all__ = ['models', 'common']
from src.models.user import User
from src.models.post import Post
from src.models.blog import Blog
If this is src/__init__.py, you can use a relative import:
from __future__ import absolute_import
from .models.user import User
from .models.post import Post
from .models.blog import Blog
I have a Flask application with this error:
ImportError: No module named annotaria, referer: http://ltw1413.web.cs.unibo.it/
So, my root in web server is:
/home/web/ltw1413/html
Inside html folder I have:
One folder named "annotaria
One file .wsgi named "wsgi.wsgi"
My file .wsgi is:
import sys
sys.path.insert(0, '/home/web/ltw1413/html')
from annotaria import app as application
Inside my folder "annotaria" I have:
"Static" folder : inside stylesheet and js
"Templates" folder : inside html
"run.py" : file python where I have my application
run.py is this:
from pydoc import html
from annotaria import app
from flask import Flask, render_template, redirect, request
import json
import urllib2
import urlparse
import re
import string
import os
from SPARQLWrapper import SPARQLWrapper, JSON
from rdflib import Graph, BNode, Literal, Namespace
from time import strftime
import urllib2
import BeautifulSoup
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/index.html')
def reloader():
return render_template('index.html')
# other app.route()...
if __name__ == '__main__':
app.run(debug=True)
How can I find a solution? Where is my error?
Lots of errors here...
annotaria is not found on path (that is why it says... well.. exactly that).
In your code you also redefine app: you import it from annotaria and then redefine it in app = Flask(...
Others mentioned individual errors, but it would be helpful to understand the big picture. First of all, let's assume the following structure:
/home/web/ltw1413/html
- wsgi.wsgi
- annotaria/
- __init.py__
- run.py
- static/
- templates
Like Klaus mentioned, you need __init__.py to tell Python that annotaria is a valid package. But then your wsgi.wsgi file needs to import the app from the run module:
from annotaria.run import app as application
You also need to remove this unnecessary import from run.py, since you instantiate a new application:
from annotaria import app
Because there is no application to import, you instantiate a new Flask application.
Finally, make sure that the app runs manually before you start deploying it.
I have built is a simple web app with Flask and Python, which I intend to upload to Heroku.
When starting my app locally, with the following script:
#!venv/bin/python
from app import app
app.run(debug = True)
I get this error message:
Traceback (most recent call last):
File "./run.py", line 2, in <module>
from app import app, mail
File "/home/ricardo/personalSite/app/__init__.py", line 3, in <module>
from app import index
File "/home/ricardo/personalSite/app/index.py", line 6, in <module>
from emails import send_email
File "/home/ricardo/personalSite/app/emails.py", line 2, in <module>
from app import app, mail
ImportError: cannot import name mail
So, it cannot import mail.
Inside the app directory I have this __init__.py, here is were I create the Mail object that is ginving me trouble to import:
from flask import Flask
app = Flask(__name__)
from app import index
from flask.ext.mail import Mail
mail = Mail(app)
And this is the file emails.py where I call the send_mail function:
from flask.ext.mail import Message
from app import app, mail
from flask import render_template
from config import ADMINS
from decorators import async
So, according to the error message, the error is in this file, in the from app import app, mail.
What is the problem? Why can't it import mail?
Update:
This is my directory listing:
persSite\
venv\
<virtual environment files>
app\
static\
templates\
__init__.py
index.py
emails.py
decorators.oy
tmp\
run.py
You have a circular dependency. You have to realize what Python is doing when it imports a file.
Whenever Python imports a file, Python looks to see if the file has already started being imported before. Thus, if module A imports module B which imports module A, then Python will do the following:
Start running module A.
When module A tries to import module B, temporarily stop running module A, and start running module B.
When module B then tries to import module A, then Python will NOT continue running module A to completion; instead, module B will only be able to import from module A the attributes that were already defined there before module B started running.
Here is app/__init__.py, which is the first file to be imported.
from flask import Flask
app = Flask(__name__)
from app import index # <-- See note below.
from flask.ext.mail import Mail
mail = Mail(app)
When this file is imported, it is just Python running the script. Any global attribute created becomes part of the attributes of the module. So, by the time you hit the third line, the attributes 'Flask' and 'app' have been defined. However, when you hit the third line, Python begins trying to import index from app. So, it starts running the app/index.py file.
This, of course, looks like the following:
from flask.ext.mail import Message
from app import app, mail # <-- Error here
from flask import render_template
from config import ADMINS
from decorators import async
Remember, when this Python file is being imported, you have thus far only defined Flask and app in the app module. Therefore, trying to import mail will not work.
So, you need to rearrange your code so that if app.index relies on an attribute in app, that app defines that attribute before attempting to import app.index.
This is probably the problem:
from app import app, mail
In the file 'app/emails.py' the import is from the current module, not a nested app module. Try:
from . import app, mail
If it doesn't work, you should update your question with a more detailed directory listing.