I've configured IIS with python and wfastcgi.py, getting it working, mostly. When trying with simple stuff, it returns the expected content.
My issue now is with getting flask and plotly/dash working under IIS, using attribute routing.
My web.config is as follows:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="Python FastCGI" path="*" verb="*" modules="FastCgiModule" scriptProcessor="C:\Python36\python.exe|C:\Python36\Scripts\wfastcgi.py" resourceType="Unspecified" requireAccess="Script" />
</handlers>
</system.webServer>
<appSettings>
<!-- Required settings -->
<add key="WSGI_HANDLER" value="index.wsgi_app" />
<add key="PYTHONPATH" value="C:/inetpub/wwwroot/python/venv/Scripts/python36.zip;C:/inetpub/wwwroot/python/venv/DLLs;C:/inetpub/wwwroot/python/venv/lib;C:/inetpub/wwwroot/python/venv/Scripts;c:/python36/Lib', 'c:/python36/DLLs;C:/inetpub/wwwroot/python/venv;C:/inetpub/wwwroot/python/venv/lib/site-packages" />
<!-- Optional settings -->
<add key="WSGI_LOG" value="C:\temp\my_app.log" />
<add key="WSGI_RESTART_FILE_REGEX" value=".*((\.py)|(\.config))$" />
<add key="APPINSIGHTS_INSTRUMENTATIONKEY" value="__instrumentation_key__" />
<add key="WSGI_PTVSD_SECRET" value="__secret_code__" />
<add key="WSGI_PTVSD_ADDRESS" value="ipaddress:port" />
</appSettings>
</configuration>
I've created an index.py file and when I use
from flask import Flask
from SimpleDash1 import app as sd1
from WebAppExampleA import app as waea
app = Flask(__name__)
#app.route("/")
def hello():
response = ["Hello, world!\n"]
return (line.encode("utf-8") for line in response)
def wsgi_app(environ,start_response):
start_response('200 OK', [('Content-type', 'text/html'), ('Content-encoding', 'utf-8')])
return hello()
if __name__ == "__main__":
app.run()
It works fine, but it doesnt exactly serve up my plotly app.
To try and load my plotly app, I've used this instead:
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from app import app
from apps import web_example_a
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
#app.callback(Output('page-content', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/apps/web_example_a':
return web_example_a.layout
#elif pathname == '/apps/app2':
# return app2.layout
else:
return '404'
if __name__ == '__main__':
app.run_server(debug=True)
But now I'm stumped as to what entrypoint I need to configure as my WSGI_HANDLER in web.config.
If I try to change the WSGI_HANDLER to "index.display_page" I get an error saying:
Error occurred:
Traceback (most recent call last): File
"C:\Python36\Scripts\wfastcgi.py", line 849, in main
for part in result: File "C:\python36\lib\site-packages\applicationinsights\requests\WSGIApplication.py",
line 70, in call
for part in self._wsgi_application(environ, status_interceptor): File "C:\python36\lib\site-packages\dash\dash.py", line 498, in
add_context
output_value = func(*args, **kwargs) TypeError: display_page() takes 1 positional argument but 2 were given
StdOut:
StdErr: C:\python36\lib\site-packages\plotly\tools.py:103:
UserWarning:
Looks like you don't have 'read-write' permission to your 'home' ('~')
directory or to our '~/.plotly' directory. That means plotly's python
api can't setup local configuration files. No problem though! You'll
just have to sign-in using 'plotly.plotly.sign_in()'. For help with
that: 'help(plotly.plotly.sign_in)'. Questions? Visit
https://support.plot.ly
The WSGI entry point for Dash apps is the Flask instance attached to the Dash instance. That means you want to point your WSGI handler at app.server (where app is the Dash instance).
WSGI servers often look for an attribute application when passed a module as an entry point. So a common thing to do is create a an entry-point file wsgi.py which in your case would simply have this:
from index import app
application = app.server
Related
I am currently working on an application using WPF + pythonnet. And I encountered a problem of using relative path in the main xaml file to find the ResourceDictionary file. Here is a minimal example. There are three files in the app folder:
app/
|-main_window.py
|-main_window.xaml
|-resource.xaml
The main_window.py stores the python code that loads and shows the window layout from the xaml files:
import os
from pathlib import Path
import clr
clr.AddReference(r"wpf\PresentationFramework")
from System.Windows import Application
from System.IO import StreamReader
from System.Windows.Markup import XamlReader
from System.Threading import ApartmentState, Thread, ThreadStart
class MainWindow:
def __init__(self):
self.xamlFilePath = os.path.join(
Path(__file__).parent,
"main_window.xaml",
)
stream = StreamReader(self.xamlFilePath)
window = XamlReader.Load(stream.BaseStream)
Application().Run(window)
if __name__ == "__main__":
thread = Thread(ThreadStart(MainWindow))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
thread.Join()
The main_window.xaml file defines the layout of the application:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="200" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="./resource.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<TextBlock>Test relative path for WPF + Pythonnet</TextBlock>
</Grid>
</Window>
And the resource.xaml stores the ResourceDictionary with the templates:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</ResourceDictionary>
Ideally, main_window.xaml should be able to find resource.xaml and load the Style tags. It works well if I provide absolute path, but for relative path it did not work. It gave an Exception: Python.Runtime.PythonException: XamlParseException
Interestingly, if I load the xaml file from Kaxaml, the resource.xaml can be found without problem.
Thanks in advance!
I am new to Flask and wanted to develop a micro-service application that can get the data from other microservice (written in spring boots) running in http://localhost:8080/users.
The data looks like this:
{"userList":[{"userId":1,"name":"x","email":"x#gmail.com","address":"add1","phone":"123","accountNo":"0000001"},{"userId":2,"name":"y","email":"x#gmail.com","address":"add1","phone":"123","accountNo":"0000001"}
My code is like below:
from flask import Flask, jsonify, request
import logging
app = Flask(__name__)
os.environ['NO_PROXY'] = '127.0.0.1'
r = request.get('http://127.0.0.1:8080')
#app.route('/users', methods=['GET'])
def cust_search(email):
json = request.get_json()
if __name__ == '__main__':
app.logger.setLevel(logging.INFO)
app.run(debug=True)
I get the below error message when I run in venv:
File "", line 13, in <module>
r = request.get('http://127.0.0.1:8080')
File "", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/covid_service/venv/lib/python3.7/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/covid_service/venv/lib/python3.7/site-packages/flask/globals.py", line 38, in _lookup_req_object
raise RuntimeError(_request_ctx_err_msg)
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.
Any help please
For what you are doing, you need to use the builtin requests module.
import requests
users = requests.get('http://127.0.0.1:8080').json()
flask.request is different than requests. It used for handling request data passed to the server, typically from a form post, and as you stated requires an active HTTP request.
I am trying to use keycloak with apache superset. I have spent hours on the links below but unable to replace the current login.
Using OpenID/Keycloak with Superset
2.Using KeyCloak(OpenID Connect) with Apache SuperSet
Using OpenID/Keycloak with Superset
I am using apache superset 0.34.5. While above links use 0.28 and below.
i am confused at inital step. let me explain the steps and see what i am missing.
I install superset using pip.
The structure i have is, i have config.py and security.py at the same level (i dont have security folder)
I renamed the security to oid_security.
I created a security.py with the following content.
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_oidc import OpenIDConnect
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import ModelView, SimpleFormView, expose
import logging
class AuthOIDCView(AuthOIDView):
#expose('/login/', methods=['GET', 'POST'])
def login(self, flag=True):
sm = self.appbuilder.sm
oidc = sm.oid
#self.appbuilder.sm.oid.require_login
def handle_login():
user = sm.auth_user_oid(oidc.user_getfield('email'))
if user is None:
info = oidc.user_getinfo(['preferred_username', 'given_name', 'family_name', 'email'])
user = sm.add_user(info.get('preferred_username'), info.get('given_name'), info.get('family_name'), info.get('email'), sm.find_role('Gamma'))
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return handle_login()
#expose('/logout/', methods=['GET', 'POST'])
def logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/') + self.appbuilder.get_url_for_login
return redirect(oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout?redirect_uri=' + quote(redirect_url))
class OIDCSecurityManager(SupersetSecurityManager):
authoidview = AuthOIDCView
def __init__(self,appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
I then created custom manager with the following
from flask_appbuilder.security.manager import AUTH_OID
from flask_appbuilder.security.sqla.manager import SecurityManager
from flask_oidc import OpenIDConnect
class OIDCSecurityManager(SecurityManager):
def __init__(self, appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
self.authoidview = AuthOIDCView
I created client secret.json with my credentials.
I edited config file as below.
from superset.security import OIDCSecurityManager
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS = 'client_secret.json'
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
One thing to mention here is have manager py in security folder in flask appbuilder which has Abstract Security Manager cls. I am getting an error security py
It says cannot import name SupersetSecurityManager from superset - security
anyone please?
I suggest you start afresh and follow the steps that worked for me:
Create a virtual environment within your superset directory and activate it.
Install the flask-oidc and superset plugins within your virtual environment. pip install flask-oidc
Have a oidc_security.py file with the script you pasted above i.e. security.py in your setup.
Have a client_secret.json file with your keycloak config.
Have a superset_config.py with the script you pasted above.
Add all three of these files to your pythonpath.
Run superset db upgrade & superset init commands.
Finally, execute superset run. After the initialization completes, navigate to http://localhost:8088 on your browser. Expected behaviour: you'll be redirected to keycloak to login/register. After successful sign in, you'll be redirected to superset app.
I hope this helps. Do post back incase you succeed or face an error.
I then created custom manager with the following
where to update this??
from flask_appbuilder.security.manager import AUTH_OID
from flask_appbuilder.security.sqla.manager import SecurityManager
from flask_oidc import OpenIDConnect
class OIDCSecurityManager(SecurityManager):
def __init__(self, appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
self.authoidview = AuthOIDCView
I have autocomplete function as a separate file - autocomplete.py. The autocomplete is being imported into init.py as follows:
from xyzapp.autocomplete import autocomplete
The line that throws error in autocomplete.py is the following:
#app.route('/autocomplete',methods=['GET'])
The structure of the application is using blueprints and looks as follows:
appcontainer
|
|--run.py
|
|
|--xyzapp
|--__init__.py
|--autocomplete.py
|--blueprint_folder_1
|--blueprint_folder_2
|--static
The whole error message looks like this:
#app.route('/autocomplete',methods=['GET'])
AttributeError: module 'flask.app' has no attribute 'route'
Any ideas what I am doing wrong?
UPDATE:
The autocomplete.py looks as follows:
from flask import Flask, render_template, redirect, url_for, request, session, flash, app, Blueprint, jsonify
#app.route('/autocomplete',methods=['GET'])
def autocomplete():
database='backbone_test'
db=client[database]
all_names=list(db.ids.find({},{"current_name":1,"_id":0}))
return json.dumps(all_names)
The __init__.py file looks as follows:
from flask import Flask, render_template, Blueprint, jsonify, session
import jinja2
class MyApp(Flask):
def __init__(self):
Flask.__init__(self, __name__)
self.jinja_loader = jinja2.ChoiceLoader([self.jinja_loader,jinja2.PrefixLoader({}, delimiter = ".")])
def create_global_jinja_loader(self):
return self.jinja_loader
def register_blueprint(self, bp):
Flask.register_blueprint(self, bp)
self.jinja_loader.loaders[1].mapping[bp.name] = bp.jinja_loader
app = MyApp()
from xyzapp.autocomplete import autocomplete
from xyzapp.blueprint_folder_1.some_file import bp_1
app.register_blueprint(bp_1)
In autocomplete.py, it looks like you're importing app from Flask and not from your __init__.py file. Try importing from __init__.py instead.
import Flask first, the initiate your app
from flask import Flask
app = Flask(__name__)
I'm sorry this is a bit of a long shot, I'm not familiar with this way of running a Flask app, but it seems you create your own instance of the Flask class called MyApp and initialise it under the variable app.
I'm not 100% and may be completely wrong, but I think your problem lies in the __init__ of MyApp
Did you import Flask to your.py? Double check and make the addition of missing.
I am so close to getting my code completed. I would like to get only the values in an array. Right now I am getting XML declaration plus the line.
Here's my code:
import groovy.xml.XmlUtil
def serverList = new
XmlSlurper().parse("/app/jenkins/jobs/firstsos_servers.xml")
def output = []
serverList.Server.find { it.#name == SERVER}.CleanUp.GZIP.File.each{
output.add(XmlUtil.serialize(it))
}
return output
Here is my XML File:
<ServerList>
<Server name="testserver1">
<CleanUp>
<GZIP>
<File KeepDays="30">log1</File>
<File KeepDays="30">log1.2</File>
</GZIP>
</CleanUp>
</Server>
<Server name="testserver2">
<CleanUp>
<GZIP>
<File KeepDays="30">log2</File>
</GZIP>
</CleanUp>
</Server>
<Server name="testserver3">
<CleanUp>
<GZIP>
<File KeepDays="30">log3</File>
</GZIP>
</CleanUp>
</Server>
When I select testserver1 my output should be:
['log1','log1.2']
What I am getting is this:
<?xml version="1.0" encoding="UTF-8"?><File KeepDays="30">log1</File>
<?xml version="1.0" encoding="UTF-8"?><File KeepDays="30">log2</File>
You need not require to use XmlUtil.serialize()
Here is what you need and following inline comments.
//Define which server you need
def SERVER = 'testserver1'
//Pass the
def serverList = new
XmlSlurper().parse("/app/jenkins/jobs/firstsos_servers.xml")
//Get the filtered file names
def output = serverList.Server.findAll{it.#name == SERVER}.'**'.findAll{it.name() == 'File'}*.text()
println output
return output
Output:
You can quickly try online Demo
def output = []
def node = serverList.Server.find {
it.'name' = 'testserver1'
}.CleanUp.GZIP.File.each {
output.add(it)
}
return output
also there is a copy & paste error in your .xml. You have to add </ServerList> at the end.
`