Flask refering to root folder circular import - python

I have a Flask application that is constructed as following:
--- /app
------ /__pycache__
------ /static
--------- /files
--------- /assets
--------- /images
------ /templates
------ api.py
------ utils.py
------ config.py
------ sftp.py
--- wsgi.py
wsgi.py:
from app.main import app
if __name__ == "__main__":
app.run()
main.py:
from flask import Flask, render_template, request, session, flash, url_for, redirect
from werkzeug.utils import secure_filename
from .utils import *
from .config import *
from .sftp import sync_work_days
app = Flask(__name__)
app.secret_key = b'very_secret_key'
[...]
config.py:
import os
from wsgi import app
ROOT_PATH = app.instance_path
sftp.py:
import pysftp as sftp
from .config import *
from .utils import upload_working_days
import time, os
from datetime import datetime
from config import ROOT_PATH
def sync_work_days():
cnopts = sftp.CnOpts()
cnopts.hostkeys = None
s = sftp.Connection(host=SFTP_HOSTNAME, username=SFTP_USERNAME, password=SFTP_PASSWORD, cnopts=cnopts)
print("Connection succesfully established...")
remoteFilePath = '/files/company'
files = s.listdir_attr(remoteFilePath)
if files == []:
return "empty"
else:
for f in files:
localFilePath = os.path.join(ROOT_PATH, 'static/files/company')
# s.get(remoteFilePath, localFilePath)
upload_working_days(localFilePath)
time.sleep(5)
print("UPLOAD DONE")
s.rename(remoteFilePath + f, remoteFilePath + "/archives/" + f)
When I run the app, I get the following error:
from wsgi import app
ImportError: cannot import name 'app' from partially initialized module 'wsgi' (most likely due to a circular import) (D:\[...redacted...]\wsgi.py)
All I want to do is to download a file via SSH and put it in app/static/files, and I can't just hardcode the path because the deployment environment is different.
UPDATE 1:
I tried to cut off config.py from the loop and I made the following changes:
sftp.py:
import pysftp as sftp
from .config import *
from .main import app
from .utils import upload_working_days
import time, os
from datetime import datetime
def sync_work_days():
cnopts = sftp.CnOpts()
cnopts.hostkeys = None
filename = os.path.join(app.instance_path, 'my_folder', 'my_file.txt')
And this is the error I get:
ImportError: cannot import name 'app' from partially initialized module 'app.main' (most likely due to a circular import) (D:\[...redacted...]\app\main.py)

You have a circular import because you are importing app in config.py from wsgi.py, which gets it from main.py which imports config.py.
And you are importing app in config.py because you need a setting from it. Have you considered keeping all your settings in config.py and importing them in main.py from there? That seems like a logical thing to do.

The solution to this problem is the following:
In sftp.py, replace:
from .main import app
by:
from . import main
and instead of using app.instance_path, use main.app.instance_path

Related

Python Flask Gunicorn Configuration says "from flask_ckeditor import CKEditor, CKEditorField ImportError: No module named flask_ckeditor"

I am using python 3.7 environments, flask framework and with the latest ckeditor 5 and I actually run it smoothly without any error in localhost with this command: python script.py. But when it comes to the gunicorn configuration, gunicorn --bind 0.0.0.0:5000 wsgi:app I'm having this error: "from flask_ckeditor import CKEditor, CKEditorField
ImportError: No module named flask_ckeditor" I really don't know what to do, I hope somebody will help me.
Here is the code:
import os
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine, Column, Integer, String, Sequence
from sqlalchemy.ext.declarative import declarative_base
from flask import Flask
import hashlib
from flask_wtf import FlaskForm
from flask_wtf import Form
from wtforms import StringField, PasswordField, BooleanField
from wtforms.validators import InputRequired, Email, Length
from flask_bootstrap import Bootstrap
from flask_jwt_extended import JWTManager
from flask_ckeditor import CKEditor, CKEditorField
db = SQLAlchemy()
jwt = JWTManager()
ckeditor = CKEditor()
def create_app(config_type): # dev, test, prod
# create flask instance
app = Flask(__name__)
app.config['CKEDITOR_SERVE_LOCAL'] = True
app.config['CKEDITOR_HEIGHT'] = '800px'
app.config['CKEDITOR_WIDTH'] = '800px'
ckeditor.init_app(app)
#app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres#localhost/catalog_db'
# setup configuration
configuration = os.path.join(os.getcwd(), 'config', config_type + '.py')
# load configuration from file
app.config.from_pyfile(configuration)
# attach flask to db instance(SQLALCHEMY)
db.init_app(app)
#attach flask to jwt
jwt.init_app(app)
Bootstrap(app)
# import blueprints
# inside app thats why app.catalog
from sales_tracking.api import api
from sales_tracking.api.get_api import get_api
from sales_tracking.api.get_api.get_all import get_all
from sales_tracking.api.post_api import post_api
from sales_tracking.api.post_api.authentications import authentications
from sales_tracking.api.post_api.bad_orders import bad_orders
from sales_tracking.api.post_api.box import box
from sales_tracking.api.post_api.breaktime import breaktime
from sales_tracking.api.post_api.change_dayoff import change_dayoff
from sales_tracking.api.post_api.check_in import check_in
from sales_tracking.api.post_api.check_in_monitoring import check_in_monitoring
from sales_tracking.api.post_api.competitors_act import competitors_act
from sales_tracking.api.post_api.competitors_promotion import competitors_promotion
from sales_tracking.api.post_api.confirmation_promotion_store import confirmation_promotion_store
from sales_tracking.api.post_api.confirmation_change_dayoff import confirmation_change_dayoff
from sales_tracking.api.post_api.confirmation_leave import confirmation_leave
from sales_tracking.api.post_api.confirmation_overtime import confirmation_overtime
from sales_tracking.api.post_api.daily_stocks import daily_stocks
from sales_tracking.api.post_api.facings import facings
from sales_tracking.api.post_api.leave import leave
from sales_tracking.api.post_api.logs_folder import logs_folder
from sales_tracking.api.post_api.mcp import mcp
from sales_tracking.api.post_api.mcp_adjustment import mcp_adjustment
from sales_tracking.api.post_api.nex import nex
from sales_tracking.api.post_api.planograms import planograms
from sales_tracking.api.post_api.product_discrepancy import product_discrepancy
from sales_tracking.api.post_api.confirmation_product_discrepancy import confirmation_product_discrepancy
from sales_tracking.api.post_api.promotions import promotions
from sales_tracking.api.post_api.request_overtime import request_overtime
from sales_tracking.api.post_api.rtv_pullout_and_create import rtv_pullout_and_create
from sales_tracking.api.post_api.shelf_availability import shelf_availability
from sales_tracking.api.post_api.stock_transfer import stock_transfer
from sales_tracking.api.post_api.tc import tc
from sales_tracking.api.post_api.tcp import tcp
from sales_tracking.api.post_api.team_attendance import team_attendance
from sales_tracking.api.post_api.update_position import update_position
from sales_tracking.api.post_api.sync_all import sync_all
from sales_tracking.web import web_initials
#reegister blueprint
app.register_blueprint(api)
app.register_blueprint(get_api)
app.register_blueprint(get_all)
app.register_blueprint(post_api)
app.register_blueprint(bad_orders)
app.register_blueprint(authentications)
app.register_blueprint(box)
app.register_blueprint(breaktime)
app.register_blueprint(change_dayoff)
app.register_blueprint(check_in)
app.register_blueprint(check_in_monitoring)
app.register_blueprint(competitors_act)
app.register_blueprint(competitors_promotion)
app.register_blueprint(confirmation_promotion_store)
app.register_blueprint(confirmation_change_dayoff)
app.register_blueprint(confirmation_leave)
app.register_blueprint(confirmation_overtime)
app.register_blueprint(daily_stocks)
app.register_blueprint(facings)
app.register_blueprint(leave)
app.register_blueprint(logs_folder)
app.register_blueprint(mcp)
app.register_blueprint(mcp_adjustment)
app.register_blueprint(nex)
app.register_blueprint(planograms)
app.register_blueprint(product_discrepancy)
app.register_blueprint(promotions)
app.register_blueprint(request_overtime)
app.register_blueprint(rtv_pullout_and_create)
app.register_blueprint(shelf_availability)
app.register_blueprint(stock_transfer)
app.register_blueprint(tc)
app.register_blueprint(tcp)
app.register_blueprint(team_attendance)
app.register_blueprint(update_position)
app.register_blueprint(web_initials)
app.register_blueprint(confirmation_product_discrepancy)
app.register_blueprint(sync_all)
return app
For anybody else having this kind weird issues. Please use python env while pip installing, that might fix the issue.
There is really good blog post by one of python core developers why you should use python -m pip instead of pip read about it here.
Add location of CKEditor static files in apache/Nginx sites-available
location /static/ckeditor/ {
root /home/username/myProject/env/lib/python3.8/site-packages/ckeditor;
}

How to reference create_app from different sub-domain?

The relevant part of my app structure looks like the following:
hp/
|
|---app/
|---admin/
|---auth/
|---errors/
|---main/
|---__init__.py
|---email.py
|---models.py
|---search.py
|---config.py
|---quiz.py
I want to create a scripts/ domain in either hp/ or app/. In those scripts I need to be able to reference config values. I'm using dotenv to do that. In order to use dotenv, I need app to be available so that I can call app.config['CONFIG_NAME'].
Here's more or less what I'm trying to do:
import requests
from app import app
access_key = app.config['ACCESS_KEY']
secret_key = app.config['SECRET_KEY']
data = requests.get(f'https://api.foo.com/search?client_id={access_key}&page=1&query=foo').json()
If I try from app import app, as I have above, I get a ModuleNotFoundError: No module named 'app' error. If I try from .. import app I get a ValueError: attempted relative import beyond top-level package error.
Any guidance/advice is greatly appreciated!
I ended up solving this by changing the sys.path.
I added the following:
import sys
import os
import inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
appdir = os.path.dirname(currentdir)
hpdir = os.path.dirname(appdir)
sys.path.insert(0, hpdir)
from app import create_app
app = create_app()
After that I was able to successfully call app.config

Can not import mongo object in other file

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.

Does __init__.py have to be in every directory of python application?

__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

Python 2.7.3 Flask ImportError: No module named

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.

Categories

Resources