I'm trying to write some unit tests for a flask application I made. The project is setup like this:
apiproject (parent folder containing everything)
/venv
run.py
requirements.txt
/project
__init__.py
/departments
__init__.py
routes.py
models.py
/users
__init__.py
routes.py
models.py
/tests
TestUsers.py
run.py:
from project import app
if __name__ == '__main__':
app.run(debug=True)
my actual app is created under project/init.py
from flask import Flask, jsonify, Response
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
from dotenv import load_dotenv
from flask_cors import CORS
load_dotenv(verbose=False)
DB_URL = os.getenv("DATABASE_URL")
# initialize the application
app = Flask(__name__)
and in my TestUsers.py I have this:
import json
from project import app
import unittest
from dotenv import load_dotenv
load_env(verbose=False)
class TestUsers(unittest.TestCase):
def setUp(self):
self.app = app
self.url_prefix = prefix = os.getenv("URL_PREFIX")
self.client = self.app.test_client()
def test_index(self):
response = self.client.get(self.url_prefix + '/')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
When I run TestUsers.py, I get ModuleNotFoundError: No module named 'project'. I tried doing sys.path.append('../') and ../../ inside of TestUsers.py, but that didn't help.
inside TestUsers.py, before importing app:
https://stackoverflow.com/a/22737042/7858114
I think you need an init.py in your apiproject folder too.
Related
My code structure. I tried but kept getting error cannot import name 'caching'. I guess my method isn't correct as caching will not have app initiation when I import caching in external file.
xyz
-app.py
-run.py
-urls
-v2.py
-resource
-views.py
-external.py
run.py
from app import create_app
if __name__ == "__main__":
career_app = create_app()
career_app.run(host=HOST,
port=PORT,
debug=True)
app.py
from flask import Flask
from flask_caching import Cache
caching = Cache(config={'CACHE_TYPE': 'simple'})
def create_app():
"""Create web app."""
app = Flask(__name__)
configure_app(app)
caching.init_app(app)
setup_blueprints(app)
return app
external.py
from app import caching
v1.py
v2_api.add_resource(UserConfigView, '/user/config',
endpoint='user_config_view')
It is a simple factory app setup
ext.py
from flask_caching import Cache
cache = Cache()
app.py
def create_app():
app = Flask(__name__)
register_extensions(app)
...
def register_extensions(app):
cache.init_app(app, config=settings.params.CACHE_CONFIG)
I am using Flask for my web framework. I am having an issue with imports. I am not understanding why can't I import my variable when I declare it within my my_app/__init__.py:
from flask import Flask
from flask_login import LoginManager
from my_app.some_module.my_class.py import auth
app = Flask(__name__)
login_manager = LoginManager()
class Config:
def __init__(self):
pass
config = Config()
My conflictuous imports are present in my_app/some_module/my_class.py:
from flask import Blueprint
from my_app import login_manager # this one works fine
from my_app import config
auth = Blueprint('auth', __name__)
I run the app with run.py:
from my_app import app
app.run(debug=True)
I then get the error:
Traceback (most recent call last):
...
File ".../my_app/some_module/my_class.py", line 1, in <module>
from my_app import login_manager, config
ImportError: cannot import name 'config' from 'my_app' (.../my_app/__init__.py)
Project structure is:
my_app
+ __init__.py
some_module
+ __init__.py
+ my_class.py
+ run.py
You have a cyclic import: my_app.some_module -> my_app.some_module.my_class -> my_app.some_module.
You can fix this by moving both Config and config to a separate module my_app.some_module.config.
# my_app.some_module.my_config
class Config:
pass
config = Config()
# my_app.some_module.my_class
from .my_config import config
# my_app.some_module.__init__
from .my_config import config
from .my_class import MyClass
This means that every import does not depend on previous imports:
my_app.some_module
|-> my_app.some_module.my_class -> my_app.some_module.config
\-> my_app.some_module.my_config
Doing imports this way instead of moving the import for .my_class to the end of __init__.py is more robust. You can freely reorder the imports of .my_class and .my_config at the top of files.
The problem is that you have a cyclic dependency. By the time you import auth from my_app.some_module.my_class.py your config is not set yet. Try moving that import to the end of the my_app/__init__.py file like:
from flask import Flask
from flask_login import LoginManager
app = Flask(__name__)
login_manager = LoginManager()
class Config:
pass
config = Config()
from my_app.some_module.my_class.py import auth
I'm trying to clean up my flask app and I decided to use a boilerplate structure. I have the auth_bp blueprint, it's defined in auth.py , I have the following folder structure;
-app_root
-application
-__init__.py
- auth.py
- other files like template and static
- config.py (for configuration)
- server.py (to run the app through flask_script )
In __init__.py I have two classes: app and mail and I need to use them in my auth.py file.
But when I write :
from application import app, mail
I get an ImportError: cannot import name app
Here's the code in __init__.py:
from flask import Flask
from flask_mail import Mail
import config
from auth import auth_bp
app = Flask(__name__)
app.config.from_object("config.Config")
mail = Mail(app)
app.register_blueprint(auth_bp)
#app.route("/")
def home():
return "homepage"
Edit : Solved: I had to import auth after creating the app and mail object.
I'm creating a personal application with flask_restful, and I was doing everything with a single models.py and app.py, but the application is going to grow so I decided to make some folder restructuring.
I currently have the following structure:
/project_folder
application_name
__init__.py
controllers.py
models.py
config.py
manage.py
run.py
tests
__init__.py
test_controller.py
Everything works so far, but I want the structure to be the following:
/project_folder
application_name
__init__.py
controllers
__init__.py
brewery_controller.py
...others
models
__init__.py
base_model.py
brewery.py
...others
config.py
manage.py
run.py
tests
__init__.py
test_controller.py
But I can't seem to make it work. Here is the application __init__.py
#/project_folder/application_name/__init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restful import Api
from controllers import BreweryList, BreweryResource
from models import db
def initApp(config):
app = Flask(__name__)
app.config.from_object(config)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
api = Api(app)
api.add_resource(BreweryList, '/breweries')
api.add_resource(BreweryResource, '/breweries/<brewery_id>')
return app
I tried with
from brewery_controller import BreweryList, BreweryResource
from base_model import db
with no luck. I keep getting ImportError: cannot import BreweryList and the same goes for db if I uncomment the Brewery classes import line.
The controllers/__init__.py and models/__init__.py are both empty.
Here is also the run.py
import os
from beerinv import initApp
if __name__ == '__main__':
app = initApp(os.environ['APP_SETTINGS'])
app.run()
Could solve the issue by following #davidism comment by putting full import path:
from application_name.controllers.brewery_controller import BreweryList, BreweryResource
from application_name.models.base_model import db
My app layout
my_app
__init__.py
my_app
__init__.py
startup
__init__.py
create_app.py
create_users.py
common_settings.py
core
__init__.py
models.py
views.py
errors
__init__.py
errors.py
Inner __init__.py
from flask import Flask
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__) # The WSGI compliant web application object
db = SQLAlchemy(app) # Setup Flask-SQLAlchemy
manager = Manager(app) # Setup Flask-Script
from my_app.startup.create_app import create_app
create_app()
create_app.py
def create_app(extra_config_settings={}):
# Load all blueprints with their manager commands, models and views
from my_app import core
return app
core/__init__.py
# from . import views
views.py
from my_app import app, db
from flask import Flask, request
#app.errorhandler(Error)
def handle_invalid_usage(error):
response = jsonify(data=error.to_dict())
response.status_code = error.status_code
return response
I based this code on a tutorial I found. Everything works fine as long as I leave the __init__.py in the core folder empty.
When I don't, I get a NameError: name Error is not defined in my views.py. Error comes from errors.py.
I have three questions:
1) Why does this happen only when I leave the import statement in core/__init__.py.
2)
create_app.py
app.config.from_envvar('ENV_SETTINGS_FILE')
# Other app.config commands here
from my_app import core
return app
What happens when from my_app import core runs?
3) Finally when I return app, is this to ensure that Inner __init__.py file contains the updated app object?
Any explanations would be greatly appreciated!
Trying to build and configure an app with dynamic imports is really bad news and confusing for the reasons you are discovering. A much better and understandable pattern would be a more typical factory:
def create_app():
app = Flask(__name__)
configure_app(app, config)
register_db(app)
add_views(app)
add_manager(app)
return app
if __name__ == '__main__':
app = create_app()
app.run()
But since you're asking, your problem is here:
from my_app import app, db
from flask import Flask, request
#app.errorhandler(Error) # Error is not imported
def handle_invalid_usage(error):
response = jsonify(data=error.to_dict())
response.status_code = error.status_code
return response
The error occurs because views.py is imported, the code compiler comes across Error and cannot find a reference to it.
For your second question: from my_app import core causes core.__init.__ to run, which (presumably) adds the views onto the app object.