I'm trying to generate an HTML report from my Unittests of Python3.6. I'm using the HTMLTestRunner library.
Here are my unit tests:
#!/usr/bin/env python
import unittest
import boto3
import warnings
import HTMLTestRunner
class SecurityGroupTest(unittest.TestCase):
def setUp(self):
session = boto3.Session(profile_name='default')
self.ec2_clt = session.client('ec2')
def test_delete_03(self):
response = self.ec2_clt.describe_security_groups()
self.assertEqual(len(response['SecurityGroups']), 0)
if __name__ == "__main__":
HTMLTestRunner.main()
When I run the tests, nothing is generated. What am I missing here?
Related
I'm looking for the simplest way to generate the same dash dashboard X times with different dataset.
Each dashboard is a single page and the main app is a flask app.
The goal is to have a dashboard template running on different dash instance with different dataset.
I started with the following code, but I'm struggling when dash pages include callbacks i.e when html.Div([html.H1('Hi there, I am app1 for reports')]) turns into a bigger function with callback
import dash
import dash_html_components as html
from flask import Flask, render_template, redirect
from werkzeug.middleware.dispatcher import DispatcherMiddleware
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello from Flask!'
#app.route('/test2')
def t2():
return render_template('test2.html')
dash_app1 = dash.Dash(__name__, server = app, url_base_pathname='/dashboard/' )
dash_app2 = dash.Dash(__name__, server = app, url_base_pathname='/reports/')
dash_app1.layout = html.Div([html.H1('Hi there, I am app1 for reports')])
dash_app2.layout = html.Div([html.H1('Hi there, I am app2 for reports')])
#app.route('/dashboard')
def render_dashboard():
return redirect('/dash1')
#app.route('/reports')
def render_reports():
return redirect('/dash2')
app = DispatcherMiddleware(app, {
'/dash1': dash_app1.server,
'/dash2': dash_app2.server
})
So my question is what is the best way/architecture to manage muti dash dashboards, based on the same template, running different data ?
In case it might help, I found a solution encapsulating the layout, callbacks and return function into a class.
flask_app.py
from flask import Flask, render_template, redirect
import dash
from apps.dashboard1 import Dashboard1
from apps.dashboard2 import Dashboard2
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello from Flask!'
#app.route('/test')
def test():
return render_template('test.html')
dash_app1 = dash.Dash(__name__, server = app, url_base_pathname='/dashboard1/' )
dash_app1.config.suppress_callback_exceptions = True
dash_app1.layout = Dashboard1(dash_app1).layout
#app.route('/dashboard1')
def render_dashboard():
return redirect('/dash1')
dash_app2 = dash.Dash(__name__, server = app, url_base_pathname='/dashboard2/')
dash_app2.config.suppress_callback_exceptions = True
dash_app2.layout = Dashboard2(dash_app2).layout
#app.route('/dashboard2')
def render_dashboard2():
return redirect('/dash2')
if __name__ == '__main__':
app.run(debug=True)
apps/dashboard1.py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
class Dashboard1:
def __init__(self, app_dependency):
self.app_dependency = app_dependency
html.P("Your code here"),
dcc.Dropdown(...),
...
dcc.Graph(id="pie-chart"),
])
#self.app_dependency.callback(
Output("pie-chart", "figure"),
Input('organisations', 'value'))
def update_output_div(selected_org):
your_update_function
return your_outputs
This is a continuation of this question.
As my flask app should not write anything in my database, I set up Flask-SQLAlchemy to reflect my database. This way I do not have to change my models, when I change my schema:
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
db.init_app(app)
with app.app_context():
db.Model.metadata.reflect(db.engine)
# app/models.py
from app import db
class Data(db.Model):
__table__ = db.Model.metadata.tables['data']
But now, if I have to import the Model before I created the app, I run into Errors because the metadata is not set yet. This is a problem when it comes to testing for example:
# test.py
import unittest
from app import create_app, db
from app.models import Data
class TestGUI(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.app = create_app()
# etc ...
This throws KeyError: 'data' in __table__ = db.Model.metadata.tables['data'] when importing from app.models as the metadata is not correctly set before the create_app() function is run.
I did find a solution (thanks to #snakecharmerb). The solution is simply to avoid the problem, to not import app.models before running create_app(). A bit hacky, so feel free to post an answer as well, when you have a better solution.
My test file now looks like this:
# test.py
import unittest
from app import create_app, db
app = create_app()
from app.models import Data
class TestGUI(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.app = app
# etc ...
I am trying to make a dashboard where the output from shap forceplot is illustrated. Shap.forceplot is HTML decorated with json. The example is here
I made a very simple dashboard using the tutorial which should plot the desirable figure after clicking the submit
here is the code
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import pandas as pd
from sqlalchemy import create_engine
import shap
from sources import *
import xgboost
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
dcc.Input(id='input-cvr-state', type='text', value='12'),
html.Button(id='submit-button', n_clicks=0, children='Submit'),
html.Div(id='output-state'),
html.Div(id='output-shap')
])
#app.callback(Output('output-shap', 'children'),
[Input('submit-button', 'n_clicks')],
[State('input-cvr-state', 'value')])
def update_shap_figure(n_clicks, input_cvr):
shap.initjs()
# train XGBoost model
X,y = shap.datasets.boston()
model = xgboost.train({"learning_rate": 0.01}, xgboost.DMatrix(X, label=y), 100)
# explain the model's predictions using SHAP values(same syntax works for LightGBM, CatBoost, and scikit-learn models)
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)
# visualize the first prediction's explanation
return(shap.force_plot(explainer.expected_value, shap_values[0,:], X.iloc[0,:])) # matplotlib=True
if __name__ == '__main__':
app.run_server(debug=True)
I managed it by following steps:
import shap
from shap.plots._force_matplotlib import draw_additive_plot
# ... class dashApp
# ... callback as method
# matplotlib=False => retrun addaptativevisualizer,
# if set to True the visualizer will render the result is the stdout directly
# x is index of wanted input
# class_1 is ma class to draw
force_plot = shap.force_plot(
self.explainer.expected_value[class_1],
self.shap_values[class_1][x[0], :],
self.data.iloc[x, :].drop(columns=["TARGET"], errors="ignore"),
matplotlib=False
)
# set show=False to force the figure to be returned
force_plot_mpl = draw_additive_plot(force_plot.data, (30, 7), show=False)
return figure_to_html_img(force_plot_mpl)
def figure_to_html_img(figure):
""" figure to html base64 png image """
try:
tmpfile = io.BytesIO()
figure.savefig(tmpfile, format='png')
encoded = base64.b64encode(tmpfile.getvalue()).decode('utf-8')
shap_html = html.Img(src=f"data:image/png;base64, {encoded}")
return shap_html
except AttributeError:
return ""
The result will be like it
An alternative is to use html.IFrame which will produce a better looking and fully interactive plot.
Here's an example that can be used directly as an Output
def _force_plot_html(*args):
force_plot = shap.force_plot(*args, matplotlib=False)
shap_html = f"<head>{shap.getjs()}</head><body>{force_plot.html()}</body>"
return html.Iframe(srcDoc=shap_html,
style={"width": "100%", "height": "200px", "border": 0})
I want to create a REST API without using Flask. I have created once using Flask as shown below but now I want to try without Flask. I came to know that urllib is one of the packages for doing it but not sure how to do. Even if there is some way other than urllib then that is also fine.
from werkzeug.wrappers import Request, Response
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
with open ("jsonfile.json") as f:
data = json.load(f)
#data=f.read()
#app.route('/', methods=['GET', 'POST'])
def hello():
return jsonify(data)
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 9000, app)
You can try something like this
import json
import http.server
import socketserver
from typing import Tuple
from http import HTTPStatus
class Handler(http.server.SimpleHTTPRequestHandler):
def __init__(self, request: bytes, client_address: Tuple[str, int], server: socketserver.BaseServer):
super().__init__(request, client_address, server)
#property
def api_response(self):
return json.dumps({"message": "Hello world"}).encode()
def do_GET(self):
if self.path == '/':
self.send_response(HTTPStatus.OK)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(bytes(self.api_response))
if __name__ == "__main__":
PORT = 8000
# Create an object of the above class
my_server = socketserver.TCPServer(("0.0.0.0", PORT), Handler)
# Star the server
print(f"Server started at {PORT}")
my_server.serve_forever()
And testing like this
→ curl http://localhost:8000
{"message": "Hello world"}%
but keep in mind that this code is not stable and just sample
You shall take an existing web server and use WSGI compatible app, for example, for Apache HTTP 2.2
Install mod_wsgi (just search how to install mod_wsgi in your operating system)
Configure mod_wsgi in Apache httpd.conf
LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias /wsgi /var/www/wsgi/myapp.wsgi
Write myapp.wsgi
The code for myapp.wsgi must call the second argument once in this way:
def application(environ, start_response):
status = '200 OK'
output = b'{"message": "Hello world"}'
response_headers = [('Content-type', 'application/json'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
im new to python code, QT and MySQL, i wanna show a data base in a QtableView but i cant it.
i dont know whats happend, the error is ('QSqlDatabase' object has no attribute 'setHotsName')
the code is:
# -*- coding: utf-8 -*-
import sys
import mysql.connector
from PyQt4 import QtSql, QtCore, QtGui, uic
form_class = uic.loadUiType("dialog.ui")[0]
def crearConexion():
db = QtSql.QSqlDatabase.addDatabase('QMYSQL')
db.setHotsName('localhots')
db.setDatabaseName('Registro')
db.setUserName('root')
db.setPassword('xxxx')
db.open()
print(db.lastError().text())
return True
class MiClase(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.model=QtSql.QSqlTableModel(self)
self.model.setTable("RegistroIN")
self.model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
self.model.select()
self.tableView.setModel(self.model)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
if not crearConexion():
sys.exit(1)
MiApp = MiClase()
MiApp.show()
sys.exit(app.exec_())
somebody that help me? thank you.