How to run function from web app locally and not on host - python-3.x

I'm want to create a web app so a user can run process locally on his computer (I know that currently it doesn't have a real usage).
So I use flask to create the web app and created a button that calls function that run the process.
Issue is the func runs on the server and not on the machine the user use.
For example to be clear: Server runs on machine 1.2.3.4, a user log the web app from a different machine 5.6.7.8 and press the button, the func will run on the host (1.2.3.4) causing the process to open on the host and not locally on user computer.
from flask import Flask, render_template, request, url_for, flash, redirect
import subprocess
def runchrome():
p = subprocess.Popen(r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe")
app = Flask(__name__)
#app.route("/home", methods=["GET", "POST"])
def home():
if request.method == "POST":
process = request.form["process"]
if process == "Chrome":
runchrome()
return render_template("Home.html")

You cannot run python code on the client's computer via a webapp in this way. Otherwise everybody could abuse this and run arbitrary code on computers that visit their websites. However, you can run javascript on the client's computer inside their browser.
For this to happen, you need to return a valid html document containing javascript. See this tutorial as a starting point: https://www.jitsejan.com/python-and-javascript-in-flask.html
Another way would be that the user installs your app on their machine.

Related

How do you host a multi-page Dash application on IIS?

I am trying to host a multi-page Dash application on IIS for internal use at work. I have been able to get single-page Dash applications, such as below to work.
from flask import Flask
import dash
import dash_html_components as html
from dash.dependencies import Input, Output
server=Flask(__name__)
app = dash.Dash(__name__, suppress_callback_exceptions=True, show_undo_redo=True, server=server)
app.layout = html.Div([])
#app.callback(Output('page-content', 'children'),
Input('url', 'pathname'))
def hello():
return "Single page dash app works but not multi-page"
if __name__ == "__main__":
app.run_server(host='0.0.0.0', port=84)
However, when I try to use it on multi-page dash applications, as described in the user manual here, it doesn't work correctly. I am able to host the application using Waitress, but would prefer something more stable and secure. IIS is how my company hosts other internal applications, so I was asked to host it that way. When attempting to use what I believe is the correct settings and handler mappings, I receive an error message on the page that simply says:
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
I believe that the issue is due to the fact that the flask application behind my Dash application is created in one script, and the entry point to the overall application is in another. I am not sure how to reconcile this, as the example page in the Dash documentation says that it must be this way.
So, how can I make this work?
cheers

Am I using application dispatching in Flask correctly?

I am fairly new to Flask applications, but well versed in Python. I have recently begun making web applications instead of regular application and I'm trying to gather some of them on a single server. Enter "Application Dispatching".
I was hoping to be able to develop an app locally and then deploy it on the server using dispatching. This means that locally I will have a script that launches the Flask app (wsgi.py), which imports stuff in the application. Now, once I add it to the dispatcher, I import the new application. This means that before the wsgi.py was a script and now it is a module - all hell breaks loose.
dispatcher.py:
from flask import Flask
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.exceptions import NotFound
from app1 import app as app1
from app2 import app as app2
from app3 import app as app3
from app4 import app as app4
app = Flask(__name__)
app.wsgi_app = DispatcherMiddleware(NotFound(), {
"/app1": app1,
'/app2': app2,
'/app3': app3,
'/app4': app4,
})
if __name__ == "__main__":
app.run()
app1\__init__.py: (works like this, but merely a proof of concept / simple app)
from flask import Flask
app = Flask(__name__)
#app.route("/")
def index_one():
return "Hi im 1"
if __name__ == "__main__":
app.run()
Both of these work - the dispatcher and the app1 can be run independently. Now, let's say I need to import a module to make app1 more functional:
from flask import Flask
import db
...
Since the dispatcher is in a parent directory, in order for it to work I need to do something like this:
from . import db
# or
from app1 import db
Now the application doesn't work independently anymore. I would like to avoid either having to refactor the application every time it needs to be deployed or adding a lot of boilerplate code like this:
if __name__ == "__main__":
import db
else:
from . import db
In any case this doesn't work when configuring the app with app.config.from_object("config.Config") as it can't be forced to be relative import (?) and otherwise can't find it without explicitly telling it which module it resides in.
From the tutorial, I got the sense that I could isolate the applications from each other:
Application dispatching is the process of combining multiple Flask
applications on the WSGI level. You can combine not only Flask
applications but any WSGI application. This would allow you to run a
Django and a Flask application in the same interpreter side by side if
you want. The usefulness of this depends on how the applications work
internally.
The fundamental difference from Large Applications as Packages is that
in this case you are running the same or different Flask applications
that are entirely isolated from each other. They run different
configurations and are dispatched on the WSGI level.
What am I doing wrong and can I get it working like I describe, by being able to launch the applications isolated or on the dispatcher, without changing my code or adding a bunch of unrelated boilerplate code to make it work?
I figured it out myself and indeed was using application dispatcher wrong. It will always integrate the different applications into one server instance.
Instead, I found out that using nginx could be used to forward to different server instances, thus completely separating the applications in each virtual environment.

Accessing file via URL

I deployed a python flask app on Heroku and it works fine. I have also uploaded a well-known folder that contains an apple-app-site association file, but when I try to access the file via URL, it returns 404. Basically, I'm testing universal links, so I wanted the apple-app-site association to be accessible. When I checked the status in the branch.io aasa validator, it returns server error, please find attached the screenshot Screenshot
What I'm doing wrong?
main.py
from flask import Flask
app = Flask(__name__, static_url_path='/well-known')
#app.route('/')
def index():
return "<h1>Welcome to Universal Link - iOS<h1>"
wsgi.py
from app.main import app
if __name__ == "__main__":
app.run()

Flask + Bokeh Server on Azure Web App Service

I want to host my bokeh server app in Azure Web App Services. Following the example in flask_embed.py I created a minimal example with a bokeh server process running on localhost:5006 and serving it with server_document in a flask route. Locally, in my computer, it runs normally without any errors:
from threading import Thread
from bokeh.embed import server_document
from bokeh.server.server import Server
from bokeh.models.widgets import Select, Div
from bokeh.layouts import column
from flask import Flask
from flask import render_template
from tornado.ioloop import IOLoop
app = Flask(__name__)
# This is the bokeh page
def modify_doc(doc):
dropdown = Select(title="Cities", options=["New York", "Berlin"])
title_row = Div(text="Home Page")
main_layout = column([
title_row,
dropdown
])
doc.add_root(main_layout)
doc.title = "My bokeh server app"
# This is the subprocess serving the bokeh page
def bk_worker():
server = Server(
{'/bkapp': modify_doc},
io_loop=IOLoop(),
allow_websocket_origin=["*"],
)
server.start()
server.io_loop.start()
Thread(target=bk_worker).start()
# This is the flask route showing the bokeh page
#app.route("/", methods=["GET"])
def my_app():
script = server_document("http://localhost:5006/bkapp")
return render_template("embed.html", script=script, template="Flask")
However, when I push it to the Azure web app, the page is blank and by inspecting the page an error message is shown:
GET https://<my-azure-site>.azurewebsites.net:5006/bkapp/autoload.js?bokeh-autoload-element=0bfb1475-9ddb-4af5-9afe-f0c4a681d7aa&bokeh-app-path=/bkapp&bokeh-absolute-url=https://<my-azure-site>.azurewebsites.net:5006/bkapp net::ERR_CONNECTION_TIMED_OUT
It seems like I don't have access to the localhost of the remote Azure server. Actually, it's not yet clear to me if the bokeh server runs/is allowed to run at all. In the server_document function I have tried putting server_document("<my-azure-site>:5006/bkapp") but the problem remains the same.
Any help is appreciated.
This post is related to another question: Bokeh embedded in flask app in azure web app
I realize this is from a while ago, but I've spent many hours in the past several days figuring this out, so this is for future people:
The issue is that server_document() is just creating a <script> tag that gets embedded into a jinja2 template, where it executes.
Locally it's not an issue because your bokeh server is running on YOUR MACHINE'S localhost:5006. To demonstrate, you can see that you can navigate directly to localhost:5006/bkapp to see your bokeh document.
Once you're hosting it on Azure, server_document() is creating the exact same script that a browser will try to execute - that is, your browser is going to try to execute a <script> tag that references localhost:5006, except that there isn't anything running on localhost:5006 because your bokeh app is actually running on Azure's server now.
I'm not sure what the best way to do it is, but the essence of it is that you need server_document() to point to the bokeh server that's running remotely. To do this you'll need to make sure that {your_remote_bokeh_server}:5006 is publicly accessible.

Serving Flask-RESTPlus on https server

I am relatively new to python and I created a micro service using flask-resplus.
Works fine on my computer and on the dev server served with http.
I dont have control on where the microservice could be deployed. In these case it seems is behind a load balancer(not sure of details), served with https.
The actual errors given by the browser: Can't read from server. It may not have the appropriate access-control-origin settings.
When i check the network developer tools i see it fails loading swagger.json. But is checking it using:
http://hostname/api/swagger.json, instead of https.
I have been googling, and i ran into discussions of this issue.
And this seemed to be the fix that could work without me having to change the library or configurations on the server.
However still i couldnt get it to work.
This is what i have:
on the api file:
api_blueprint = Blueprint('api', __name__, url_prefix='/api')
api = Api(api_blueprint, doc='/doc/', version='1.0', title='My api',
description="My api")
on the main app file:
from flask import Flask
from werkzeug.contrib.fixers import ProxyFix
from lib.api import api_blueprint
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
app.register_blueprint(api_blueprint)
Also tried adding:
app.config['SERVER_URL'] = 'http://testfsdf.co.za' # but it dont look like is being considered
Using flask-restplus==0.9.2,
Any solution will be appreciated, as long as i dont need to make configurations on the container where the service will be deployed
(am ok with setting environment variables), i.e. service need to be self contained. And if there is a version of flask-resplus that i can install with pip, that already has a fix i can appreciate.
Thanks a lot guys,
Overide API class with _scheme='https' option in spec property.
class MyApi(Api):
#property
def specs_url(self):
"""Monkey patch for HTTPS"""
scheme = 'http' if '5000' in self.base_url else 'https'
return url_for(self.endpoint('specs'), _external=True, _scheme=scheme)
api = MyApi(api_blueprint, doc='/doc/', version='1.0', title='My api',
description="My api")
The solution above works like a charm. There are couple of things you should check.
Before applying the fix, make sure in your chrome developertools -> Network tab that whenever you reload the page(in https server) that shows the swagger UI, you get a mixed content error for swagger.json request.
The solution in the above post solves the issue when deployed on an https server but locally it might give issue. For that you can use the environment variable trick.
Set a custom environment variable or any variable which is already there on your https server while deploying your app. Check for the existence of that environment variable before applying the solution to make sure your app in running in the https server.
Now when you run the app locally, this hack won't be applied and swagger.json would be served through http and in your server it would be served via https. Implementation might look similar to this.
import os
from flask import url_for
from flask_restplus import Api
app = Flask( __name__)
if os.environ.get('CUSTOM_ENV_VAR'):
#property
def specs_url(self):
return url_for(self.endpoint('specs'), _external=True, _scheme='https')
Api.specs_url = specs_url
api = Api(app)

Resources