mirror of
https://github.com/bendtherules/pytest_gui_status.git
synced 2026-08-18 21:52:18 +00:00
Added gui htmlpy code, todo.txt - maintain it
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import htmlPy
|
||||
from utils import render_template
|
||||
import os
|
||||
import redis
|
||||
import dateutil.parser
|
||||
from datetime import datetime
|
||||
import humanfriendly
|
||||
import os.path
|
||||
|
||||
|
||||
env_redis_port = os.environ.get("pytest_status_port")
|
||||
if env_redis_port:
|
||||
REDIS_PORT = int(env_redis_port)
|
||||
else:
|
||||
REDIS_PORT = 5946
|
||||
|
||||
|
||||
class Controller(htmlPy.Object):
|
||||
# GUI callable functions have to be inside a class.
|
||||
# The class should be inherited from htmlPy.Object.
|
||||
dict_state_desc = {
|
||||
"start": "Starting Tests",
|
||||
"collect": "Collecting Tests",
|
||||
"runtest": "Running Tests",
|
||||
"end": "Finished Tests"
|
||||
}
|
||||
|
||||
def __init__(self, app_gui):
|
||||
super(Controller, self).__init__()
|
||||
self.i = 0
|
||||
self.app_gui = app_gui
|
||||
self.last_state = None
|
||||
# Initialize the class here, if required.
|
||||
|
||||
@htmlPy.Slot()
|
||||
def redraw(self):
|
||||
# from main import app as app_gui
|
||||
print(self.app_gui.dir_name)
|
||||
|
||||
redis_db = redis.StrictRedis(host='localhost', port=REDIS_PORT, db=0)
|
||||
# make sure that this is correct redis db
|
||||
try:
|
||||
assert redis_db.get("PYTEST_STATUS_DB") == "1"
|
||||
except AssertionError, e:
|
||||
print("Got redis db, but it is not related to pytest status")
|
||||
raise e
|
||||
dir_name = self.app_gui.dir_name
|
||||
hash_dir_name = redis_db.hget("directories_to_hash", dir_name)
|
||||
|
||||
if hash_dir_name is None:
|
||||
raise Exception("dir_name = {dir_name} not found in redis db".format(
|
||||
dir_name=dir_name))
|
||||
|
||||
dict_state = {}
|
||||
dict_state["dir_name"] = dir_name
|
||||
dict_state["dir_name_topfolder"] = os.path.basename(dir_name)
|
||||
|
||||
dict_state["state"] = redis_db.get("{hash_a}_state".format(hash_a=hash_dir_name))
|
||||
dict_state["state_desc"] = self.dict_state_desc[dict_state["state"]]
|
||||
dict_state["last_updated"] = redis_db.get("{hash_a}_last_updated".format(hash_a=hash_dir_name))
|
||||
|
||||
dict_state["last_updated_obj"] = dateutil.parser.parse(dict_state["last_updated"])
|
||||
last_updated_rel = (datetime.now() - dict_state["last_updated_obj"]).seconds # in seconds
|
||||
if last_updated_rel > 60:
|
||||
# when >1 min, reolve only upto min
|
||||
last_updated_rel = last_updated_rel - (last_updated_rel % 60)
|
||||
dict_state["last_updated_friendly"] = humanfriendly.format_timespan(last_updated_rel)
|
||||
|
||||
dict_state["collect"] = redis_db.lrange("{hash_a}_collect".format(hash_a=hash_dir_name), 0, -1)
|
||||
dict_state["pass"] = redis_db.lrange("{hash_a}_pass".format(hash_a=hash_dir_name), 0, -1)
|
||||
dict_state["fail"] = redis_db.lrange("{hash_a}_fail".format(hash_a=hash_dir_name), 0, -1)
|
||||
dict_state["skip"] = redis_db.lrange("{hash_a}_skip".format(hash_a=hash_dir_name), 0, -1)
|
||||
|
||||
if (not self.last_state) or (self.last_state != dict_state):
|
||||
print("called redraw")
|
||||
self.app_gui.html = render_template(self.app_gui, "index.html", dict_state)
|
||||
|
||||
self.last_state = dict_state
|
||||
@@ -0,0 +1,44 @@
|
||||
import htmlPy
|
||||
import os
|
||||
import sys
|
||||
from PyQt4.QtGui import QApplication
|
||||
import PyQt4.QtCore as QtCore
|
||||
|
||||
# Import back-end functionalities
|
||||
from gui_backend import Controller
|
||||
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
dir_name_raw = sys.argv[1]
|
||||
else:
|
||||
dir_name_raw = "."
|
||||
dir_name = os.path.abspath(dir_name_raw)
|
||||
|
||||
# GUI initializations
|
||||
app = htmlPy.AppGUI(title=u"{dir_name} - Test Status".format(dir_name=dir_name),
|
||||
developer_mode=True, width=150, height=80)
|
||||
app.window.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
|
||||
screen_geo = QApplication.desktop().availableGeometry()
|
||||
screen_topright = screen_geo.topRight()
|
||||
app.x_pos = (screen_topright.x() - 20) - app.width
|
||||
app.y_pos = (screen_topright.y() + 20)
|
||||
# import pdb;pdb.set_trace()
|
||||
|
||||
# GUI configarg
|
||||
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
app.static_path = os.path.join(BASE_DIR, "static/")
|
||||
app.template_path = os.path.join(BASE_DIR, "tmpl/")
|
||||
app.dir_name = dir_name
|
||||
|
||||
# Register back-end functionalities
|
||||
app_backend = Controller(app)
|
||||
app.bind(app_backend)
|
||||
|
||||
# GUI render config
|
||||
# app.html = u""
|
||||
app_backend.redraw()
|
||||
|
||||
|
||||
# Start application
|
||||
if __name__ == "__main__":
|
||||
app.start()
|
||||
@@ -0,0 +1,109 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{dir_name}}</title>
|
||||
<style>
|
||||
*
|
||||
{
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body
|
||||
{
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
}
|
||||
.last-test-statusviz
|
||||
{
|
||||
width: 100%;
|
||||
height: 1.5em;
|
||||
}
|
||||
.statusdot
|
||||
{
|
||||
height: 100%;
|
||||
{% if collect|length > 0 %}
|
||||
width: {{100/(collect|length)}}%;
|
||||
{% else %}
|
||||
width: 0;
|
||||
{% endif %}
|
||||
/*width: 1em;*/
|
||||
padding: 1px;
|
||||
float: left;
|
||||
}
|
||||
.statusdot-fill
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.fill-pass
|
||||
{
|
||||
background-color: green;
|
||||
}
|
||||
.fill-fail
|
||||
{
|
||||
background-color: red;
|
||||
}
|
||||
.last-test-statusviz
|
||||
{
|
||||
overflow: hidden;
|
||||
border: 2px solid black;
|
||||
}
|
||||
.last-test-timerelative
|
||||
{
|
||||
font-size: 0.75em;
|
||||
height: 1em;
|
||||
/*overflow: hidden;*/
|
||||
}
|
||||
.last-test-dirname
|
||||
{
|
||||
font-size: 0.75em;
|
||||
/*height: 1em;*/
|
||||
/*position: relative;*/
|
||||
}
|
||||
/*.last-test-dirname-redacted
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 999px;
|
||||
font-size: 0.75em;
|
||||
text-align: right;
|
||||
}*/
|
||||
|
||||
</style>
|
||||
<!-- <script type="text/javascript" src="./refresh.js"></script> -->
|
||||
<script type="text/javascript">
|
||||
// debugger
|
||||
document.onload = setInterval(function(){Controller.redraw()},1000)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="section-last-test">
|
||||
<div class="state">
|
||||
{{ state_desc }}
|
||||
</div>
|
||||
<div class="last-test-statusviz">
|
||||
{% for testname in collect %}
|
||||
<div class="statusdot statusdot-{{loop.index0}}">
|
||||
<!-- {{ testname }} -->
|
||||
{% if testname in pass %}
|
||||
<div class="statusdot-fill fill-pass"></div>
|
||||
{% elif testname in fail %}
|
||||
<div class="statusdot-fill fill-fail"></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="last-test-timerelative">
|
||||
Got {{ last_updated_friendly }} ago
|
||||
</div>
|
||||
<div class="last-test-dirname">
|
||||
Folder : {{ dir_name_topfolder }}
|
||||
<!-- <div class="last-test-dirname-redacted"> -->
|
||||
<!-- </div> -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
setTimeout(Controller.redraw, 500)
|
||||
@@ -0,0 +1,13 @@
|
||||
Todo
|
||||
------
|
||||
|
||||
1. move rendering update to js using diff-dom + nunjucks ( to be decided )
|
||||
2. (-done manually, add tests)check intermediate test steps like collect, testrun
|
||||
3. In plugin, set attributes in chunk using pipeline, using `with`
|
||||
|
||||
Done
|
||||
------
|
||||
|
||||
1. (---) Get dirname from cmdline
|
||||
2. (---) responsive width of test
|
||||
3. (---) Time should update automatically
|
||||
@@ -0,0 +1,8 @@
|
||||
import jinja2
|
||||
import os
|
||||
|
||||
|
||||
def render_template(app, tmpl_name, tmpl_params):
|
||||
with open(os.path.join(app.template_path, tmpl_name)) as f_tmpl:
|
||||
tmpl_content = f_tmpl.read()
|
||||
return jinja2.Template(tmpl_content).render(tmpl_params)
|
||||
Reference in New Issue
Block a user