Multiple Bokeh Server Integration To Flask - python

I am trying to run multiple Bokeh servers in the flask app , the plots function correctly on their own using method like this:
def getTimePlot():
script = server_document('http://localhost:5006/timeseries')
return render_template("displaytimeseries.html", script=script, template="Flask")
def startPlotserver():
server.start()
server = Server({'/timeseries': modifyTimeSeries}, io_loop=IOLoop(), allow_websocket_origin=["localhost:8000"])
server.io_loop.start()
if __name__ == '__main__':
print('Opening single process Flask app with embedded Bokeh application on http://localhost:8000/')
print()
print('Multiple connections may block the Bokeh app in this configuration!')
print('See "flask_gunicorn_embed.py" for one way to run multi-process')
app.run(port=5000, debug=True)
but when i try to embed two servers together to flask using this approach that's where i get the problems:
file structure:
|--app4
|---webapp2.py
|---bokeh
|--timeseries.py
|--map.py
I think i have found the workaround in here Link To Question
I am have trying now to import the map server to flak using the similar method mentioned and ended up with something like this:
1. File builder (not sure why it's not picking it up)
def build_single_handler_applications(paths, argvs=None):
applications = {}
argvs = {} or argvs
for path in paths:
application = build_single_handler_application(path, argvs.get(path, []))
route = application.handlers[0].url_path()
if not route:
if '/' in applications:
raise RuntimeError("Don't know the URL path to use for %s" % (path))
route = '/'
applications[route] = application
return applications
2. Code to find file and create connection
files=[]
for file in os.listdir("bokeh"):
if file.endswith('.py'):
file="map"+file
files.append(file)
argvs = {}
urls = []
for i in files:
argvs[i] = None
urls.append(i.split('\\')[-1].split('.')[0])
host = 'http://localhost:5006/map'
apps = build_single_handler_applications(files, argvs)
bokeh_tornado = BokehTornado(apps, extra_websocket_origins=["localhost:8000"])
bokeh_http = HTTPServer(bokeh_tornado)
sockets, port = bind_sockets("localhost:8000", 5000)
bokeh_http.add_sockets(sockets)
3. Code which calls the server and renders template
#app.route('/crimeMap', methods=['GET'])
def getCrimeMap():
bokeh_script = server_document("http://localhost:5006:%d/map" % port)
return render_template("displaymap1.html", bokeh_script=bokeh_script)
i am running both of my Bokeh servers in single command like this
bokeh serve timeseries.py map.py --allow-websocket-origin=127.0.0.1:5000
but when i run webapp2.py i am getting this error:
(env1) C:\Users\Dell1525\Desktop\flaskapp\env1\app4>webapp2.py
Traceback (most recent call last):
File "C:\Users\Dell1525\Desktop\flaskapp\env1\app4\webapp2.py", line 113, in <module>
apps = build_single_handler_applications(files, argvs)
File "C:\Users\Dell1525\Desktop\flaskapp\env1\app4\webapp2.py", line 29, in build_single_handler_applications
application = build_single_handler_application(path, argvs.get(path, []))
NameError: name 'build_single_handler_application' is not defined
i found and added build_single_handler_application function from Bokeh docs only because of this error so i am not sure if it was even required or is correct. I am wondering what am i missing to make this work just in case it is positioning error or missing imports i am attaching full flask webapp2.py code here :
Full Code
Thak you so much for help

i have found an easier solution by tweaking this example a little: Link To Original Post Note this requires you to have tornado 4.4.1 as its not working with newer versions
trick is to run all servers individually and on different ports with same socket access like this
bokeh serve timeseries.py --port 5100 --allow-websocket-origin=localhost:5567
bokeh serve map.py --port 5200 --allow-websocket-origin=localhost:5567
for those who might find this useful i have included full working solution Link To Working Code

Related

Error while calling the send_file function from another file in python flask | RuntimeError: Working outside of request context

Greetings stack overflow community, I am currently working on a flask app and I am trying to retrieve a file from a helper function with the send_file method in flask.
I have a route that goes like so:
#app.route("/process",methods=['GET','POST'])
def do_something():
process = threading.Thread(target=function_name,args=[arg1,arg2])
process.start()
return render_template("template.html")
The function_name (which is on a different file) function is suposed to return a file like so
def function_name():
filename = 'ohhey.pdf'
return send_file(filename,as_attachment=True,cache_timeout=0)
When I run my app like this I get the following error
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context(). See the
documentation for more information.
So I try to change the function for the following:
def function_name():
filename = 'ohhey.pdf'
with app.app_context():
return send_file(filename,as_attachment=True,cache_timeout=0)
and get this new error
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that needed
an active HTTP request. Consult the documentation on testing for
information about how to avoid this problem.
so I try the following:
def function_name():
filename = 'ohhey.pdf'
with app.test_request_context():
return send_file(filename,as_attachment=True,cache_timeout=0)
After making this final change my app doesn't return a file or an error. I appreciate your help.

subprocess.Popen fails in nginx

I am developing a simple website using Flask + gunicorn + nginx on a Raspberry Pi with Rasbian Jessie.
I am stuck at launching a process with this Python code:
def which(program):
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
return None
mplayer_path = which("mplayer")
try:
player = subprocess.Popen([mplayer_path, mp3], stdin=subprocess.PIPE)
except:
return render_template('no_mp3s.html', mp3_message=sys.exc_info())
"mp3" is the path to an mp3 file while "mplayer_path" is the absolute path to mplayer, as returned by the which function described in this answer.
The code works in development when I launch flask directly. In production, when I access the website through nginx, I get the following error message through the no_mp3s.html template:
type 'exceptions.AttributeError'
AttributeError("'NoneType' object has no attribute 'rfind'",)
traceback object at 0x7612ab98
I suspect a permission issue with nginx, but being very new with Linux I am a bit lost!
Edit:
I should add that nowhere in my code (which fits in a single file) I call rfind(). Also, I am sure that the error is caught in this specific try/except because it is the only one that outputs to no_mp3s.html.
Edit:
Following blubberdiblub comments I found out that it is the which function that does not work when the app is run in nginx. Hard coding the path to mplayer seems to work!

ZEO ZODB database - run locally not working

I tried looking at the documentation for running ZEO on a ZODB database, but it isn't working how they say it should.
I can get a regular ZODB running fine, but I would like to make the database accessible by several processes for a program, so I am trying to get ZEO to work.
I created this script in a folder with a subfolder zeo, which will hold the "database.fs" files created by the make_server function in a different parallel process:
CODE:
from ZEO import ClientStorage
import ZODB
import ZODB.config
import os, time, site, subprocess, multiprocessing
# make the server in for the database in a separate process with windows command
def make_server():
runzeo_path = site.getsitepackages()[0] + "\Lib\site-packages\zeo-4.0.0-py2.7.egg\ZEO\\runzeo.py"
filestorage_path = os.getcwd() + '\zeo\database.fs'
subprocess.call(["python", runzeo_path, "-a", "127.0.0.1:9100", "-f" , filestorage_path])
if __name__ == "__main__":
server_process = multiprocessing.Process(target = make_server)
server_process.start()
time.sleep(5)
storage = ClientStorage.ClientStorage(('localhost', 9100), wait=False)
db = ZODB.DB(storage)
connection = db.open()
root = connection.root()
the program will just block at the ClientStorage line if the wait=False is not given.
If the wait=False is given it produces this error:
Error Message:
Traceback (most recent call last):
File "C:\Users\cbrown\Google Drive\EclipseWorkspace\NewSpectro - v1\20131202\2 - database\zeo.py", line 17, in <module>
db = ZODB.DB(storage)
File "C:\Python27\lib\site-packages\zodb-4.0.0-py2.7.egg\ZODB\DB.py", line 443, in __init__
temp_storage.load(z64, '')
File "C:\Python27\lib\site-packages\zeo-4.0.0-py2.7.egg\ZEO\ClientStorage.py", line 841, in load
data, tid = self._server.loadEx(oid)
File "C:\Python27\lib\site-packages\zeo-4.0.0-py2.7.egg\ZEO\ClientStorage.py", line 88, in __getattr__
raise ClientDisconnected()
ClientDisconnected
Here is the output from the cmd prompt for my process which runs a server:
------
2013-12-06T21:07:27 INFO ZEO.runzeo (7460) opening storage '1' using FileStorage
------
2013-12-06T21:07:27 WARNING ZODB.FileStorage Ignoring index for C:\Users\cab0008
\Google Drive\EclipseWorkspace\NewSpectro - v1\20131202\2 - database\zeo\databas
e.fs
------
2013-12-06T21:07:27 INFO ZEO.StorageServer StorageServer created RW with storage
s: 1:RW:C:\Users\cab0008\Google Drive\EclipseWorkspace\NewSpectro - v1\20131202\
2 - database\zeo\database.fs
------
2013-12-06T21:07:27 INFO ZEO.zrpc (7460) listening on ('127.0.0.1', 9100)
What could I be doing wrong? I just want this to work locally right now so there shouldn't be any need for fancy web stuff.
You should use proper process management and simplify your life. You likely want to look into supervisor, which can be responsible for running/starting/stopping your application and ZEO.
Otherwise, you need to look at the double-fork trick to daemonize ZEO -- but why bother when a process management tool like supervisor does this for you.
If you are savvy with relational database administration, and already have a relational database at your disposal -- you can also consider RelStorage as a very good ZODB (low-level) storage backend.
In Windows you should use double \ instead of a single \ in the paths. Easy and portable way to accomplish this is to use os.path.join() function, eg. os.path.join('os.getcwd()', 'zeo', 'database.fs'). Otherwise a similar code worked ok for me.
Had same error on Windows , on Linux everything OK ...
your code is ok , to make this to work change following
C:\Python33\Lib\site-packages\ZEO-4.0.0-py3.3.egg\ZEO\zrpc\trigger.py ln:235
self.trigger.send(b'x')
C:\Python33\Lib\site-packages\ZEO-4.0.0-py3.3.egg\ZEO\zrpc\client.py ln:458:459 - comment them
here is those lines:
if socktype != socket.SOCK_STREAM:
continue

cannot access webserver resources using virtualenv and webapp2

I wanted to create a simple app using webapp2. Because I have Google App Engine installed, and I want to use it outside of GAE, I followed the instructions on this page: http://webapp-improved.appspot.com/tutorials/quickstart.nogae.html
This all went well, my main.py is running, it is handling requests correctly. However, I can't access resources directly.
http://localhost:8080/myimage.jpg or http://localhost:8080/mydata.json
always returns a 404 resource not found page.
It doesn't matter if I put the resources on the WebServer/Documents/ or in the folder where the virtualenv is active.
Please help! :-)
(I am on a Mac 10.6 with Python 2.7)
(Adapted from this question)
Looks like webapp2 doesn't have a static file handler; you'll have to roll your own. Here's a simple one:
import mimetypes
class StaticFileHandler(webapp2.RequestHandler):
def get(self, path):
# edit the next line to change the static files directory
abs_path = os.path.join(os.path.dirname(__file__), path)
try:
f = open(abs_path, 'r')
self.response.headers.add_header('Content-Type', mimetypes.guess_type(abs_path)[0])
self.response.out.write(f.read())
f.close()
except IOError: # file doesn't exist
self.response.set_status(404)
And in your app object, add a route for StaticFileHandler:
app = webapp2.WSGIApplication([('/', MainHandler), # or whatever it's called
(r'/static/(.+)', StaticFileHandler), # add this
# other routes
])
Now http://localhost:8080/static/mydata.json (say) will load mydata.json.
Keep in mind that this code is a potential security risk: It allows any visitors to your website to read everything in your static directory. For this reason, you should keep all your static files to a directory that doesn't contain anything you'd like to restrict access to (e.g. the source code).

Reload Flask app when template file changes

By default, when running Flask application using the built-in server (Flask.run), it monitors its Python files and automatically reloads the app if its code changes:
* Detected change in '/home/xion/hello-world/app.py', reloading
* Restarting with reloader
Unfortunately, this seems to work for *.py files only, and I don't seem to find any way to extend this functionality to other files. Most notably, it would be extremely useful to have Flask restart the app when a template changes. I've lost count on how many times I was fiddling with markup in templates and getting confused by not seeing any changes, only to find out that the app was still using the old version of Jinja template.
So, is there a way to have Flask monitor files in templates directory, or does it require diving into the framework's source?
Edit: I'm using Ubuntu 10.10. Haven't tried that on any other platforms really.
After further inquiry, I have discovered that changes in templates indeed are updated in real time, without reloading the app itself. However, this seems to apply only to those templates that are passed to flask.render_template.
But it so happens that in my app, I have quite a lot of reusable, parametrized components which I use in Jinja templates. They are implemented as {% macro %}s, reside in dedicated "modules" and are {% import %}ed into actual pages. All nice and DRY... except that those imported templates are apparently never checked for modifications, as they don't pass through render_template at all.
(Curiously, this doesn't happen for templates invoked through {% extends %}. As for {% include %}, I have no idea as I don't really use them.)
So to wrap up, the roots of this phenomenon seems to lie somewhere between Jinja and Flask or Werkzeug. I guess it may warrant a trip to bug tracker for either of those projects :) Meanwhile, I've accepted the jd.'s answer because that's the solution I actually used - and it works like a charm.
you can use
TEMPLATES_AUTO_RELOAD = True
From http://flask.pocoo.org/docs/1.0/config/
Whether to check for modifications of the template source and reload it automatically. By default the value is None which means that Flask checks original file only in debug mode.
In my experience, templates don't even need the application to restart to be refreshed, as they should be loaded from disk everytime render_template() is called. Maybe your templates are used differently though.
To reload your application when the templates change (or any other file), you can pass the extra_files argument to Flask().run(), a collection of filenames to watch: any change on those files will trigger the reloader.
Example:
from os import path, walk
extra_dirs = ['directory/to/watch',]
extra_files = extra_dirs[:]
for extra_dir in extra_dirs:
for dirname, dirs, files in walk(extra_dir):
for filename in files:
filename = path.join(dirname, filename)
if path.isfile(filename):
extra_files.append(filename)
app.run(extra_files=extra_files)
See here: http://werkzeug.pocoo.org/docs/0.10/serving/?highlight=run_simple#werkzeug.serving.run_simple
When you are working with jinja templates, you need to set some parameters. In my case with python3, I solved it with the following code:
if __name__ == '__main__':
app.jinja_env.auto_reload = True
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.run(debug=True, host='0.0.0.0')
You need to set a TEMPLATES_AUTO_RELOAD property as True in your app config:
from flask import Flask
app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True
See more on http://flask.pocoo.org/docs/1.0/config/
Actually for me TEMPLATES_AUTO_RELOAD = True does not work (0.12 version). I use jinja2 and what i have done:
Create function before_request
def before_request():
app.jinja_env.cache = {}
Register it in application
app.before_request(before_request)
That's it.
Updated as of March 2021:
The flask CLI is recommended over app.run() for running a dev server, so if we want to use the CLI then the accepted solution can't be used.
In Flask 1.1 or later, the environment variable FLASK_RUN_EXTRA_FILES or the option --extra-files effectively do the same thing as the accepted answer. See also this github issue.
Example usage:
flask run --extra-files "app/templates/index.html"
# or
export FLASK_RUN_EXTRA_FILES="app/templates/index.html"
flask run
in Linux. To specify multiple extra files, separate file paths with colons., e.g.
export FLASK_RUN_EXTRA_FILES="app/templates/index.html:app/templates/other.html"
Whole directories are also supported:
flask run --extra-files app/templates/
What worked for me is just adding this:
#app.before_request
def before_request():
# When you import jinja2 macros, they get cached which is annoying for local
# development, so wipe the cache every request.
if 'localhost' in request.host_url or '0.0.0.0' in request.host_url:
app.jinja_env.cache = {}
(taken from #dikkini's answer)
To reload the application on the server AND in the browser I used the livereload package. Installed through the CLI with
$ pip install livereload
and running the code
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def hello():
return render_template("index.html")
if __name__ == '__main__':
from livereload import Server
server = Server(app.wsgi_app)
server.serve(host = '0.0.0.0',port=5000)
all answers here using the extra_files argument or TEMPLATES_AUTO_RELOAD config work to reload it on the server but for a smooth development experience without damaging your keyboard's F5 key I'd go with livereload
Using the latest version of Flask on Windows, using the run command and debug set to true; Flask doesn't need to be reset for changes to templates to be brought in to effect. Try Shift+F5 (or Shift plus the reload button) to make sure nothing it being cached.
See http://flask.pocoo.org/docs/1.0/quickstart/
and use FLASK_ENV=development
I had the same trouble. The solution is really simple though. Instead of this:
if __name__ == '__main__':
app.jinja_env.auto_reload = True
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.run(debug=True)
Put
app.jinja_env.auto_reload = True
app.config["TEMPLATES_AUTO_RELOAD"] = True
above the main function. So final output for example:
from flask import Flask, app,render_template
app= Flask(__name__)
app.jinja_env.auto_reload = True
app.config["TEMPLATES_AUTO_RELOAD"] = True
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
Templates are reloaded automatically, why not doing ctrl+f5 to refresh the webpage,
cause web-browsers usually save cache.
Adding app.config['TEMPLATES_AUTO_RELOAD'] = True after if __name__ == '__main__': doesn't work for me!
What works is adding app.config['TEMPLATES_AUTO_RELOAD'] = True after app = Flask(__name__)
Notice that I am using app.run(debug=True)

Categories

Resources