Why can't WSGI configuration file find my Python variable? - python

I am trying to setup PythonAnywhere with a simple Python app but the WSGI config doesn't seem to be able to import properly, what am I doing wrong?
#!/usr/bin/python3.6
import web
import urllib
from xml.dom import minidom
... [code] ...
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
#app.wsgifunc()
and my WSGI is as follows
#!/usr/bin/python3.6
import sys
path = "/home/myUsername"
if path not in sys.path:
sys.path.append(path)
from myPythonFileNameInSameDir import app as application
application.wsgifunc()

PythonAnywhere dev here -- when you import your web.py app from the WSGI file, it won't run anything in the if __name__ == "__main__": section.
You need to do this in the app:
#!/usr/bin/python3.6
import web
import urllib
from xml.dom import minidom
... [code] ...
app = web.application(urls, globals())
if __name__ == "__main__":
app.run()
...and this in the WSGI file:
#!/usr/bin/python3.6
import sys
path = "/home/myUsername"
if path not in sys.path:
sys.path.append(path)
from myPythonFileNameInSameDir import app
application = app.wsgifunc()

Related

ImportError: cannot import name 'app' from 'FlaskApp' (unknown location)

I have been following this tutorial from digital ocean.
I got all the way to the last step when I get a 500 Internal Server Error.
My app is structured like the following:
|--------FlaskApp
|----------------FlaskApp
|-----------------------static
|-----------------------templates
|-----------------------venv
|-----------------------__init__.py
|----------------flaskapp.wsgi
My __init__.py contains the following:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello, I love Digital Ocean!"
if __name__ == "__main__":
app.run()
My flaskapp.wsgi contains the following:
import sys
import logging
import site
site.addsitedir('/var/www/FlaskApp/venv/lib/python3.7/site-packages')
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/FlaskApp/")
from FlaskApp import app as application
application.secret_key = 'key'
I had added the bit about importing site after reading this SO
When I look into /var/www/FlaskApp/venv/lib/python3.7/site-packages I can in fact see that packages I need and when I run python3, and import flask, it does load.
Thanks for your help in advance!

How to get rid of extra cgi-bin url components running a Flask App using wsgiref CGIHandler?

I am on a shared cpanel hosting plan that does not support wsgi apps directly. So I have to use the wsgiref CGIHandler workaround, as described here: http://flask.pocoo.org/docs/0.12/deploying/cgi/ .
It all works and produces expected results, but there is always this extra stuff in the urls: "/cgi-bin/index.cgi/" that the python app seems to be adding automatically (to match what it detects while called by the cgi handler).
For example, I would like it to be myhost.com/login/ instead of myhost.com/cgi-bin/index.cgi/login/, or myhost.com/ instead of myhost.com/cgi-bin/index.cgi/.
All those shorter versions of the links work well, because of the engine rewrite rules are in place. I have checked that. It is just a matter of finding a way to tell the flask app to get rid of "/cgi-bin/index.cgi/".
Some of my code:
cat www/.htaccess
# Redirect everything to CGI WSGI handler, but Don't interfere with static files
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /cgi-bin/index.cgi/$1 [L]
.
cat www/cgi-bin/index.cgi
#!/home/myhost/myhost.com/flasky/venv/bin/python
import os
import sys
sys.path.insert(0, '/home/myhost/myhost.com/flasky/venv/lib/python2.7/site-packages')
sys.path.insert(0, '/home/myhost/myhost.com/flasky')
from wsgiref.handlers import CGIHandler
from manage import app
CGIHandler().run(app)
.
cat www/flasky/manage.py
#!/usr/bin/env python
import os
from app import create_app, db
from app.models import User, Role, Permission
from flask_script import Manager, Shell
from flask_migrate import Migrate, MigrateCommand
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role,
Permission=Permission)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
.
Any ideas?
Thanks!
I have found a hack for it.. but it's just a hack :-(
If I override the value of SCRIPT_NAME environment variable in the wsgiref CGIHandler script, it works perfectly then.
Here's the updated code:
cat www/cgi-bin/index.cgi
#!/home/myhost/myhost.com/flasky/venv/bin/python
import os
import sys
sys.path.insert(0, '/home/myhost/myhost.com/flasky/venv/lib/python2.7/site-packages')
sys.path.insert(0, '/home/myhost/myhost.com/flasky')
from wsgiref.handlers import CGIHandler
from manage import app
os.environ['SCRIPT_NAME'] = ''
CGIHandler().run(app)
.
Basically, whatever the os.environ['SCRIPT_NAME'] value is, it gets prefixed to the flask app url every time a page is requested.
I am still looking for a more elegant "pythonic" solution though ..
cat www/cgi-bin/index.cgi
#!/home/myhost/myhost.com/flasky/venv/bin/python
import os
import sys
sys.path.insert(0, '/home/myhost/myhost.com/flasky/venv/lib/python2.7/site-packages')
sys.path.insert(0, '/home/myhost/myhost.com/flasky')
from wsgiref.handlers import CGIHandler
from manage import app
class ScriptNameStripper(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
environ['SCRIPT_NAME'] = ''
return self.app(environ, start_response)
app = ScriptNameStripper(app)
CGIHandler().run(app)

Why does Flask's app.config.from_object() behave differently with gunicorn?

I'm using Flask with virtualenv, and my demo Flask app is structured as follows:
app/
hello.py
config/
settings.py
venv/
virtualenv files
Contents of hello.py
from flask import Flask
def create_app():
app = Flask(__name__, instance_relative_config=True)
app.config.from_object("config.settings")
#app.route('/')
def index():
return app.config["HELLO"]
return app
if __name__ == "__main__":
app = create_app()
app.run()
settings.py contains just 2 values
DEBUG = True
HELLO = "Hello there from /config !"
I can run this successfully with gunicorn using gunicorn -b 0.0.0.0:9000 --access-logfile - "app.hello:create_app()", it works without any errors.
However, running python app/hello.py from root results in the error ImportError: No module named 'config'. It seems that flask is unable to find the config directory when executed in this manner.
I could move the config directory inside app, but doing so would cause errors with gunicorn instead. Is it not possible to have both ways "just work" ? More importantly, why and what is happening ?
Not the most elegant yet still perfectly working solution:
from os.path import abspath, join
from flask import Flask
def create_app():
app = Flask(__name__, instance_relative_config=True)
config_file_path = abspath(
join(app.instance_path, '../config/settings.py')
)
app.config.from_pyfile(config_file_path)
#app.route('/')
def index():
return app.config["HELLO"]
return app
if __name__ == "__main__":
app = create_app()
app.run()
Addition after considering the comment. In order for Flask to properly import config.settings, the path to app root has to be inside sys.path. It can easily be achieved by adding a single line in the original script:
sys.path.insert(0, os.getcwd())
So the final hello.py looks like:
import os
import sys
from flask import Flask
def create_app():
app = Flask(__name__, instance_relative_config=True)
sys.path.insert(0, os.getcwd())
app.config.from_object("config.settings")
#app.route('/')
def index():
return app.config["HELLO"]
return app
if __name__ == "__main__":
app = create_app()
app.run()
Even more bullet-proof solution would be
app_root_path = os.path.abspath(
os.path.join(app.instance_path, '..')
)
sys.path.insert(0, app_root_path)
This way we do not depend on what os.getcwd() returns: it does not always have to return the app root path.

Flask __init__.py import error

I can not import functions from other files to __init__.py in a flask. Importing something from a file gets an error 500.
__init__.py
from flask import Flask
from fel import fel
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == '__main__':
app.run(debug=True)
fel.py
def fel(a,b):
c = a+b
return (c)
If I delete the following line in the __init__.py file
from fel import fel
Everything is OK.
__init__.py and fel.py are in the same directory
I am working in Python 3.4
Where is the mistake?
edit:
structures
FlaskApp\
__init__.py
fel.py
use relative import
from .fel import fel
fel(something)
Explanation:
The problem of import fel is that you don't know whether its an
absolute import or a relative import. fel could a module in python's
path, or a package in the current module.
Source https://softwareengineering.stackexchange.com/questions/159503/whats-wrong-with-relative-imports-in-python
Your import should be:
from FlaskApp.fel import fel
And the parent directory of FlaskApp needs to be present in your sys.path somehow (for example, set the PYTHONPATH environment variable).
just
from flask import Flask
from .fel import fel
app = Flask(__name__)
#app.route('/')
def hello_world():
number = fel(4,6)
return (number)
if __name__ == '__main__':
app.run(debug=True)

NameError: name 'helloworld' is not defined

My files are as follows:
helloworld.py
from flask import Flask
app = Flask(__name__)
#app.route('/')
def __init__(self):
print 'Hello World!'
if __name__ == '__main__':
app.run()
application.wsgi
import os
import sys
sys.path.append('/srv/www/mysite.com/application')
os.environ['PYTHON_EGG_CACHE'] = '/srv/www/mysite.com/.python-egg'
import flaskr.helloworld
application = helloworld
When attempting to run this through my web browser, the module is loaded fine. I end up receiving a 500 error, with this in my error.log "NameError: name 'helloworld' is not defined"
Any ideas why?
Thank you in advance.
import flaskr.helloworld as helloworld
application = helloworld.app
Or alternatively:
import flaskr.helloworld
application = flaskr.helloworld.app
In application.wsgi, how about replacing the last line with
application = flaskr.helloworld
Or replace the import with
import flaskr.helloworld as helloworld

Categories