New to Py and Python. I'm trying to get pyramid Configurator scan to find my views, but I seem to be missing something, it's not picking up my "view" index here are my files:
app.py
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
if __name__ == '__main__':
config = Configurator()
config.add_route('home', '/')
config.scan()
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 6543, app)
server.serve_forever()
and index.py
from pyramid.view import view_config
from pyramid.response import Response
#view_config(route_name='home')
def index(request):
print'Incoming request'
return Response('<body><h1>Home</h1></body>')
Its returning a 404. However, if I remove config.scan() and add the view manually it works fine.
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from index import index
if __name__ == '__main__':
config = Configurator()
config.add_route('home', '/')
config.add_view(index, route_name='home')
From Pyramid documentation
scan(package=None, categories=None, onerror=None, ignore=None, **kw)[source]
Scan a Python package and any of its subpackages for objects marked with configuration decoration such as pyramid.view.view_config. Any decorated object found will influence the current configuration state.
The package argument should be a Python package or module object (or a dotted Python name which refers to such a package or module). If package is None, the package of the caller is used. In this case it is looking for decorations in app package or app.py file.
To fix this add
config.scan(package='index')
or rename app.py to __init__.py
Related
I'm trying to make a Flask api :
app.py
routes
-> __init__.py
-> myobject.py
# app.py
from flask import Flask
from flask_restful import Api
from routes import MyObject
app = Flask(__name__)
api = Api(app)
api.add_resource(MyObject, '/')
if __name__ == '__main__':
app.run()
# __init__.py
from myobject import MyObject
# myobject.py
from flask_restful import Resource
class MyObject(Resource):
def get(self):
return {'hello': 'world'}
When I run my application (python app.py), I get a ModuleNotFoundError: No module named 'myobject'
I don't understand why python can't find my module myobject. Is there something i'm missing in my __init__.py
For __init__.py, it also needs the relative import or absolute import path in order to work correctly.
# __init__.py
# relative import
from .myobject import MyObject
# absolute import
from routes.myobject import MyObject
In another approach, you can write to import MyObject more specifically like this and leave __init__.py an empty file.
# app.py
# ...
from routes.myobject import MyObject
# ...
I believe the problem is due to your app running in the "main" directory and your import residing in a sub directory. Basically your app thinks you are trying to import "/main/myobject.py" instead of "/main/routes/myobject.py"
Change your import in __init__ to from .myobject import MyObject
The . means "this directory" (essentially).
I'm converting a cli application to use a REST api and I've read up on flask and I thought I understood things but apparently not :-D. based on this: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
I have a directory structure:
--myApp
myApp.py
--APIService
__init__.py
WebService.py
myApp.py:
from APIService import app
app.run(debug = True )
init:
from flask import Flask
app = Flask(__name__)
from app import routes
WebService.py:
from APIService import app
class WebService(object):
'''
classdocs
'''
def __init__(self,):
'''
Constructor
'''
#app.route('/')
#app.route('/index')
def index():
return "Hello, World!"
I've tried this a few different ways like renaming app to APIService but I keep circling back to the same error: APIService\__init__.py", line 5, in <module> from app import routes ImportError: No module named app
I just don't get what I'm doing wrong here. I did pip install flask so the module is there. I skipped the environment part but that's because I wasn't bothered with running globally for now. anyone have a clue as to what I messed up?
In the following line insideAPIService\__init__.py:
from app import routes
the keyword routes is referencing a separate Python Module inside the APIService folder that is named "routes.py" in the Flask Mega Tutorial. It seems like you have renamed the "routes.py" file to "WebService.py" so you can solve the import issue by changing the import line insideAPIService\__init__.pyto:
from app import WebService
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)
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.
The Tumblelog app on the MongoDB site does not work .
I've followed the example absolutely and I get a 404 error when I run it in my local host. I'm using Eclipse Indigo (3.7.2) with pyDev on Ubuntu 12.0.4.
I'm not sure if it's because of the register_blueprints, which I included in the __init__.py
I did it like this as in the tutorial:
from flask import Flask
from flask.ext.mongoengine import MongoEngine
app = Flask(__name__)
app.config["MONGODB_DB"] = "my_tumble_log"
app.config["SECRET_KEY"] = "KeepThisS3cr3t"
db = MongoEngine(app)
if __name__ == '__main__':
app.run()
def register_blueprints(app):
# Prevents circular imports
from tumblelog.views import posts
app.register_blueprint(posts)
register_blueprints(app)
Otherwise I have followed the tutorial exactly.
register_blueprints is never called - app.run blocks until you kill the script (at which point there is no point to adding routes).
Change the order and everything will run:
def register_blueprints(app):
# Prevents circular imports
from tumblelog.views import posts
app.register_blueprint(posts)
register_blueprints(app)
if __name__ == '__main__':
app.run()
regist_blueprints is not actually preventing circular imports - the pattern to avoid circular imports is to create the app in a different file and import both app and blueprint into a third file to run everything:
# application.py
from flask import Flask # etc.
app = Flask("your_package_name")
# tumblelog/views.py
from flask import Blueprint, current_app # etc.
posts = Blueprint("tumblelog")
#posts.route("/")
def index():
# use current_app rather than app here
# run_server.py (use the same pattern for .wsgi files)
from application import app
from tumblelog.views import posts
app.register_blueprint(posts)
if __name__ == "__main__":
app.run()