Big update, AppVeyor_Test
This commit is contained in:
parent
aec570d055
commit
e71faf0b92
65 changed files with 2141 additions and 1355 deletions
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from _ed_lrr import *
|
||||
|
||||
from .preprocess import Preprocessor
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import multiprocessing as MP
|
||||
import queue
|
||||
import ctypes
|
||||
import os
|
||||
from datetime import datetime
|
||||
from math import floor
|
||||
import click
|
||||
from tqdm import tqdm
|
||||
from click_default_group import DefaultGroup
|
||||
import requests as RQ
|
||||
from urllib.parse import urljoin
|
||||
from ed_lrr_gui import Router, Preprocessor, cfg
|
||||
from _ed_lrr import find_sys
|
||||
from _ed_lrr import PyRouter
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
|
||||
|
||||
|
@ -43,9 +45,8 @@ def main(ctx):
|
|||
MP.freeze_support()
|
||||
if ctx.invoked_subcommand != "config":
|
||||
os.makedirs(cfg["folders.data_dir"], exist_ok=True)
|
||||
if ctx.invoked_subcommand is None:
|
||||
ctx.invoke(gui)
|
||||
return
|
||||
if ctx.invoked_subcommand==None:
|
||||
click.forward(gui_main)
|
||||
return
|
||||
|
||||
|
||||
|
@ -55,18 +56,20 @@ def main(ctx):
|
|||
@click.option("--debug", "-d", is_flag=True, help="Run using debug server")
|
||||
def web(host, port, debug):
|
||||
"Run web interface."
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from ed_lrr_gui.web import app
|
||||
|
||||
with app.test_client() as c:
|
||||
c.get("/") # Force before_first_request hook to run
|
||||
if debug:
|
||||
app.debug=True
|
||||
app.debug = True
|
||||
app.run(host=host, port=port, debug=True)
|
||||
return
|
||||
print("Listening on {}:{}".format(host, port))
|
||||
server = WSGIServer((host, port), app)
|
||||
server.serve_forever()
|
||||
else:
|
||||
print("Listening on {}:{}".format(host, port))
|
||||
server = WSGIServer((host, port), app)
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
@main.command()
|
||||
|
@ -175,7 +178,7 @@ def download(url, folder):
|
|||
unit_divisor=1024,
|
||||
unit_scale=True,
|
||||
ascii=True,
|
||||
smoothing=0
|
||||
smoothing=0,
|
||||
) as pbar:
|
||||
with open(download_path, "wb") as of:
|
||||
resp = RQ.get(
|
||||
|
@ -224,7 +227,7 @@ def preprocess(systems, bodies, output):
|
|||
preproc.start()
|
||||
state = {}
|
||||
pstate = {}
|
||||
while not (preproc.queue.empty() and preproc.is_alive() == False):
|
||||
while not (preproc.queue.empty() and not preproc.is_alive()):
|
||||
try:
|
||||
event = preproc.queue.get(True, 0.1)
|
||||
state.update(event)
|
||||
|
@ -309,7 +312,7 @@ def preprocess(systems, bodies, output):
|
|||
"-m",
|
||||
default=cfg["route.mode"],
|
||||
help="Search mode",
|
||||
type=click.Choice(["bfs","bfs_old", "a-star", "greedy"]),
|
||||
type=click.Choice(["bfs", "bfs_old", "a-star", "greedy"]),
|
||||
show_default=True,
|
||||
)
|
||||
@click.option(
|
||||
|
@ -358,7 +361,7 @@ def route(**kwargs):
|
|||
kwargs["factor"],
|
||||
None,
|
||||
kwargs["path"],
|
||||
kwargs["workers"]
|
||||
kwargs["workers"],
|
||||
]
|
||||
with click.progressbar(
|
||||
length=100,
|
||||
|
@ -429,5 +432,9 @@ def precompute(*args, **kwargs):
|
|||
raise NotImplementedError
|
||||
|
||||
|
||||
def gui_main():
|
||||
return gui(False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pathlib
|
||||
from collections import namedtuple
|
||||
import profig
|
||||
|
@ -9,6 +10,8 @@ config_dir.mkdir(parents=True, exist_ok=True)
|
|||
config_file = config_dir / "config.ini"
|
||||
config_file.touch()
|
||||
|
||||
config_dir = str(config_dir)
|
||||
|
||||
cfg = profig.Config(str(config_file), strict=True)
|
||||
|
||||
cfg.init(
|
||||
|
@ -55,8 +58,8 @@ cfg.init("folders.data_dir", os.path.join(config_dir, "data"), comment="Data dir
|
|||
|
||||
cfg.init("GUI.theme", "dark", comment="GUI theme to use")
|
||||
|
||||
cfg.init("web.port",3777,comment="Port to bind to")
|
||||
cfg.init("web.host","0.0.0.0",comment="Address to bind to")
|
||||
cfg.init("web.debug",False,comment="Run using debug server")
|
||||
cfg.init("web.port", 3777, comment="Port to bind to")
|
||||
cfg.init("web.host", "0.0.0.0", comment="Address to bind to")
|
||||
cfg.init("web.debug", False, comment="Run using debug server")
|
||||
|
||||
cfg.sync()
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .main import main
|
||||
|
|
|
@ -15,7 +15,9 @@ class Ui_ED_LRR(object):
|
|||
ED_LRR.setObjectName("ED_LRR")
|
||||
ED_LRR.setEnabled(True)
|
||||
ED_LRR.resize(577, 500)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(ED_LRR.sizePolicy().hasHeightForWidth())
|
||||
|
@ -26,10 +28,14 @@ class Ui_ED_LRR(object):
|
|||
ED_LRR.setDocumentMode(False)
|
||||
ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded)
|
||||
self.centralwidget = QtWidgets.QWidget(ED_LRR)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.centralwidget.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.centralwidget.setSizePolicy(sizePolicy)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
|
||||
|
@ -49,27 +55,39 @@ class Ui_ED_LRR(object):
|
|||
self.formLayout.setObjectName("formLayout")
|
||||
self.lbl_bodies_dl = QtWidgets.QLabel(self.tab_download)
|
||||
self.lbl_bodies_dl.setObjectName("lbl_bodies_dl")
|
||||
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl)
|
||||
self.formLayout.setWidget(
|
||||
1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl
|
||||
)
|
||||
self.lbl_systems_dl = QtWidgets.QLabel(self.tab_download)
|
||||
self.lbl_systems_dl.setObjectName("lbl_systems_dl")
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl)
|
||||
self.formLayout.setWidget(
|
||||
3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl
|
||||
)
|
||||
self.inp_bodies_dl = QtWidgets.QComboBox(self.tab_download)
|
||||
self.inp_bodies_dl.setEditable(True)
|
||||
self.inp_bodies_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
self.inp_bodies_dl.setObjectName("inp_bodies_dl")
|
||||
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl)
|
||||
self.formLayout.setWidget(
|
||||
1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl
|
||||
)
|
||||
self.inp_systems_dl = QtWidgets.QComboBox(self.tab_download)
|
||||
self.inp_systems_dl.setEditable(True)
|
||||
self.inp_systems_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
self.inp_systems_dl.setObjectName("inp_systems_dl")
|
||||
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl)
|
||||
self.formLayout.setWidget(
|
||||
3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl
|
||||
)
|
||||
self.gridLayout = QtWidgets.QGridLayout()
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.inp_bodies_dest_dl = QtWidgets.QComboBox(self.tab_download)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.inp_bodies_dest_dl.setSizePolicy(sizePolicy)
|
||||
self.inp_bodies_dest_dl.setEditable(False)
|
||||
self.inp_bodies_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
|
@ -85,10 +103,14 @@ class Ui_ED_LRR(object):
|
|||
self.btn_systems_dest_browse_dl.setObjectName("btn_systems_dest_browse_dl")
|
||||
self.gridLayout_2.addWidget(self.btn_systems_dest_browse_dl, 0, 1, 1, 1)
|
||||
self.inp_systems_dest_dl = QtWidgets.QComboBox(self.tab_download)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.inp_systems_dest_dl.setSizePolicy(sizePolicy)
|
||||
self.inp_systems_dest_dl.setEditable(False)
|
||||
self.inp_systems_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
|
@ -111,57 +133,79 @@ class Ui_ED_LRR(object):
|
|||
self.formLayout_3.setObjectName("formLayout_3")
|
||||
self.lbl_bodies_pp = QtWidgets.QLabel(self.tab_preprocess)
|
||||
self.lbl_bodies_pp.setObjectName("lbl_bodies_pp")
|
||||
self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp)
|
||||
self.formLayout_3.setWidget(
|
||||
0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp
|
||||
)
|
||||
self.gr_bodies_pp = QtWidgets.QGridLayout()
|
||||
self.gr_bodies_pp.setObjectName("gr_bodies_pp")
|
||||
self.btn_bodies_browse_pp = QtWidgets.QPushButton(self.tab_preprocess)
|
||||
self.btn_bodies_browse_pp.setObjectName("btn_bodies_browse_pp")
|
||||
self.gr_bodies_pp.addWidget(self.btn_bodies_browse_pp, 0, 1, 1, 1)
|
||||
self.inp_bodies_pp = QtWidgets.QComboBox(self.tab_preprocess)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.inp_bodies_pp.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.inp_bodies_pp.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.inp_bodies_pp.setSizePolicy(sizePolicy)
|
||||
self.inp_bodies_pp.setEditable(False)
|
||||
self.inp_bodies_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
self.inp_bodies_pp.setObjectName("inp_bodies_pp")
|
||||
self.gr_bodies_pp.addWidget(self.inp_bodies_pp, 0, 0, 1, 1)
|
||||
self.formLayout_3.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp)
|
||||
self.formLayout_3.setLayout(
|
||||
0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp
|
||||
)
|
||||
self.lbl_systems_pp = QtWidgets.QLabel(self.tab_preprocess)
|
||||
self.lbl_systems_pp.setObjectName("lbl_systems_pp")
|
||||
self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp)
|
||||
self.formLayout_3.setWidget(
|
||||
1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp
|
||||
)
|
||||
self.gr_systems_pp = QtWidgets.QGridLayout()
|
||||
self.gr_systems_pp.setObjectName("gr_systems_pp")
|
||||
self.btn_systems_browse_pp = QtWidgets.QPushButton(self.tab_preprocess)
|
||||
self.btn_systems_browse_pp.setObjectName("btn_systems_browse_pp")
|
||||
self.gr_systems_pp.addWidget(self.btn_systems_browse_pp, 0, 1, 1, 1)
|
||||
self.inp_systems_pp = QtWidgets.QComboBox(self.tab_preprocess)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.inp_systems_pp.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.inp_systems_pp.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.inp_systems_pp.setSizePolicy(sizePolicy)
|
||||
self.inp_systems_pp.setEditable(False)
|
||||
self.inp_systems_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
self.inp_systems_pp.setObjectName("inp_systems_pp")
|
||||
self.gr_systems_pp.addWidget(self.inp_systems_pp, 0, 0, 1, 1)
|
||||
self.formLayout_3.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp)
|
||||
self.formLayout_3.setLayout(
|
||||
1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp
|
||||
)
|
||||
self.lbl_out_pp = QtWidgets.QLabel(self.tab_preprocess)
|
||||
self.lbl_out_pp.setObjectName("lbl_out_pp")
|
||||
self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_out_pp)
|
||||
self.gr_out_grid_pp = QtWidgets.QGridLayout()
|
||||
self.gr_out_grid_pp.setObjectName("gr_out_grid_pp")
|
||||
self.btn_out_browse_pp = QtWidgets.QPushButton(self.tab_preprocess)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.btn_out_browse_pp.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.btn_out_browse_pp.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.btn_out_browse_pp.setSizePolicy(sizePolicy)
|
||||
self.btn_out_browse_pp.setObjectName("btn_out_browse_pp")
|
||||
self.gr_out_grid_pp.addWidget(self.btn_out_browse_pp, 0, 1, 1, 1)
|
||||
self.inp_out_pp = QtWidgets.QComboBox(self.tab_preprocess)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.inp_out_pp.sizePolicy().hasHeightForWidth())
|
||||
|
@ -170,10 +214,14 @@ class Ui_ED_LRR(object):
|
|||
self.inp_out_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop)
|
||||
self.inp_out_pp.setObjectName("inp_out_pp")
|
||||
self.gr_out_grid_pp.addWidget(self.inp_out_pp, 0, 0, 1, 1)
|
||||
self.formLayout_3.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp)
|
||||
self.formLayout_3.setLayout(
|
||||
2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp
|
||||
)
|
||||
self.btn_preprocess = QtWidgets.QPushButton(self.tab_preprocess)
|
||||
self.btn_preprocess.setObjectName("btn_preprocess")
|
||||
self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess)
|
||||
self.formLayout_3.setWidget(
|
||||
3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess
|
||||
)
|
||||
self.tabs.addTab(self.tab_preprocess, "")
|
||||
self.tab_route = QtWidgets.QWidget()
|
||||
self.tab_route.setObjectName("tab_route")
|
||||
|
@ -181,14 +229,18 @@ class Ui_ED_LRR(object):
|
|||
self.formLayout_2.setObjectName("formLayout_2")
|
||||
self.lbl_sys_lst = QtWidgets.QLabel(self.tab_route)
|
||||
self.lbl_sys_lst.setObjectName("lbl_sys_lst")
|
||||
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst)
|
||||
self.formLayout_2.setWidget(
|
||||
0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst
|
||||
)
|
||||
self.gr_sys = QtWidgets.QGridLayout()
|
||||
self.gr_sys.setObjectName("gr_sys")
|
||||
self.btn_sys_lst_browse = QtWidgets.QPushButton(self.tab_route)
|
||||
self.btn_sys_lst_browse.setObjectName("btn_sys_lst_browse")
|
||||
self.gr_sys.addWidget(self.btn_sys_lst_browse, 0, 1, 1, 1)
|
||||
self.inp_sys_lst = QtWidgets.QComboBox(self.tab_route)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.inp_sys_lst.sizePolicy().hasHeightForWidth())
|
||||
|
@ -221,32 +273,44 @@ class Ui_ED_LRR(object):
|
|||
self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode)
|
||||
self.chk_permute = QtWidgets.QCheckBox(self.tab_route)
|
||||
self.chk_permute.setObjectName("chk_permute")
|
||||
self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.chk_permute)
|
||||
self.formLayout_2.setWidget(
|
||||
4, QtWidgets.QFormLayout.LabelRole, self.chk_permute
|
||||
)
|
||||
self.gridLayout_4 = QtWidgets.QGridLayout()
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route)
|
||||
self.chk_permute_keep_last.setObjectName("chk_permute_keep_last")
|
||||
self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 3, 1, 1)
|
||||
self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.chk_permute_keep_first.sizePolicy().hasHeightForWidth())
|
||||
sizePolicy.setHeightForWidth(
|
||||
self.chk_permute_keep_first.sizePolicy().hasHeightForWidth()
|
||||
)
|
||||
self.chk_permute_keep_first.setSizePolicy(sizePolicy)
|
||||
self.chk_permute_keep_first.setTristate(False)
|
||||
self.chk_permute_keep_first.setObjectName("chk_permute_keep_first")
|
||||
self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 2, 1, 1)
|
||||
self.lbl_keep = QtWidgets.QLabel(self.tab_route)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth())
|
||||
self.lbl_keep.setSizePolicy(sizePolicy)
|
||||
self.lbl_keep.setObjectName("lbl_keep")
|
||||
self.gridLayout_4.addWidget(self.lbl_keep, 0, 1, 1, 1)
|
||||
self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4)
|
||||
self.formLayout_2.setLayout(
|
||||
4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4
|
||||
)
|
||||
self.lst_sys = QtWidgets.QTreeWidget(self.tab_route)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
|
||||
sizePolicy = QtWidgets.QSizePolicy(
|
||||
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
|
||||
)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.lst_sys.sizePolicy().hasHeightForWidth())
|
||||
|
@ -353,17 +417,27 @@ class Ui_ED_LRR(object):
|
|||
|
||||
def retranslateUi(self, ED_LRR):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
ED_LRR.setWindowTitle(_translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter"))
|
||||
ED_LRR.setWindowTitle(
|
||||
_translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter")
|
||||
)
|
||||
self.lbl_bodies_dl.setText(_translate("ED_LRR", "bodies.json"))
|
||||
self.lbl_systems_dl.setText(_translate("ED_LRR", "systemsWithCoordinates.json"))
|
||||
self.inp_bodies_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/bodies.json"))
|
||||
self.inp_systems_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json"))
|
||||
self.inp_bodies_dl.setCurrentText(
|
||||
_translate("ED_LRR", "https://www.edsm.net/dump/bodies.json")
|
||||
)
|
||||
self.inp_systems_dl.setCurrentText(
|
||||
_translate(
|
||||
"ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json"
|
||||
)
|
||||
)
|
||||
self.btn_bodies_dest_browse_dl.setText(_translate("ED_LRR", "..."))
|
||||
self.btn_systems_dest_browse_dl.setText(_translate("ED_LRR", "..."))
|
||||
self.btn_download.setText(_translate("ED_LRR", "Download"))
|
||||
self.label.setText(_translate("ED_LRR", "Download path"))
|
||||
self.label_2.setText(_translate("ED_LRR", "Download path"))
|
||||
self.tabs.setTabText(self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download"))
|
||||
self.tabs.setTabText(
|
||||
self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download")
|
||||
)
|
||||
self.lbl_bodies_pp.setText(_translate("ED_LRR", "bodies.json"))
|
||||
self.btn_bodies_browse_pp.setText(_translate("ED_LRR", "..."))
|
||||
self.lbl_systems_pp.setText(_translate("ED_LRR", "systemsWithCoordinates.json"))
|
||||
|
@ -371,7 +445,9 @@ class Ui_ED_LRR(object):
|
|||
self.lbl_out_pp.setText(_translate("ED_LRR", "Output"))
|
||||
self.btn_out_browse_pp.setText(_translate("ED_LRR", "..."))
|
||||
self.btn_preprocess.setText(_translate("ED_LRR", "Preprocess"))
|
||||
self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess"))
|
||||
self.tabs.setTabText(
|
||||
self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")
|
||||
)
|
||||
self.lbl_sys_lst.setText(_translate("ED_LRR", "System List"))
|
||||
self.btn_sys_lst_browse.setText(_translate("ED_LRR", "..."))
|
||||
self.btn_add.setText(_translate("ED_LRR", "Add"))
|
||||
|
@ -393,8 +469,12 @@ class Ui_ED_LRR(object):
|
|||
self.chk_primary.setText(_translate("ED_LRR", "Primary Stars Only"))
|
||||
self.lbl_mode.setText(_translate("ED_LRR", "Mode"))
|
||||
self.btn_go.setText(_translate("ED_LRR", "GO!"))
|
||||
self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route"))
|
||||
self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log"))
|
||||
self.tabs.setTabText(
|
||||
self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")
|
||||
)
|
||||
self.tabs.setTabText(
|
||||
self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")
|
||||
)
|
||||
self.menu_file.setTitle(_translate("ED_LRR", "File"))
|
||||
self.menuWindow.setTitle(_translate("ED_LRR", "Window"))
|
||||
self.menuStyle.setTitle(_translate("ED_LRR", "Style"))
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import csv
|
||||
import gzip
|
||||
import multiprocessing as MP
|
||||
|
@ -474,7 +475,7 @@ class ED_LRR(Ui_ED_LRR):
|
|||
greedyness,
|
||||
precomp,
|
||||
path,
|
||||
os.cpu_count()-1
|
||||
os.cpu_count() - 1,
|
||||
)
|
||||
if not self.current_job:
|
||||
self.bar_status.showMessage("Computing Route...")
|
||||
|
@ -492,7 +493,7 @@ class ED_LRR(Ui_ED_LRR):
|
|||
greedyness,
|
||||
precomp,
|
||||
path,
|
||||
os.cpu_count()-1
|
||||
os.cpu_count() - 1,
|
||||
)
|
||||
else:
|
||||
self.error("there is already a job running!")
|
||||
|
|
|
@ -25,7 +25,9 @@ class Ui_diag_route(object):
|
|||
self.lst_route.setAlternatingRowColors(True)
|
||||
self.lst_route.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||
self.lst_route.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem)
|
||||
self.lst_route.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||
self.lst_route.setHorizontalScrollMode(
|
||||
QtWidgets.QAbstractItemView.ScrollPerPixel
|
||||
)
|
||||
self.lst_route.setItemsExpandable(False)
|
||||
self.lst_route.setAllColumnsShowFocus(False)
|
||||
self.lst_route.setObjectName("lst_route")
|
||||
|
@ -53,7 +55,11 @@ class Ui_diag_route(object):
|
|||
self.lst_route.headerItem().setText(0, _translate("diag_route", "Num"))
|
||||
self.lst_route.headerItem().setText(1, _translate("diag_route", "System"))
|
||||
self.lst_route.headerItem().setText(2, _translate("diag_route", "Body"))
|
||||
self.lst_route.headerItem().setText(3, _translate("diag_route", "Distance (Ls)"))
|
||||
self.chk_copy.setText(_translate("diag_route", "Auto-copy next hop to clipboard"))
|
||||
self.lst_route.headerItem().setText(
|
||||
3, _translate("diag_route", "Distance (Ls)")
|
||||
)
|
||||
self.chk_copy.setText(
|
||||
_translate("diag_route", "Auto-copy next hop to clipboard")
|
||||
)
|
||||
self.btn_close.setText(_translate("diag_route", "Close"))
|
||||
self.btn_export.setText(_translate("diag_route", "Export"))
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import jinja2
|
||||
import os
|
||||
|
||||
|
@ -10,6 +11,7 @@ def dist(p1, p2):
|
|||
s += (c1 - c2) ** 2
|
||||
return s ** 0.5
|
||||
|
||||
|
||||
colors = {
|
||||
"O": "#0000FF",
|
||||
"B": "#140AF0",
|
||||
|
|
|
@ -155,4 +155,4 @@
|
|||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import queue
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import queue
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
|
@ -20,7 +21,7 @@ class Router(Process):
|
|||
self.queue.put({"status": state})
|
||||
|
||||
def run(self):
|
||||
print("Route(): ",self.args,self.kwargs)
|
||||
print("Route(): ", self.args, self.kwargs)
|
||||
route = _ed_lrr.route(*self.args, **self.kwargs)
|
||||
self.queue.put({"return": route})
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from .app import app, templates, db
|
||||
|
|
|
@ -1,28 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from flask import (
|
||||
Flask,
|
||||
jsonify,
|
||||
session,
|
||||
render_template,
|
||||
redirect,
|
||||
url_for,
|
||||
send_from_directory,
|
||||
request,
|
||||
flash,
|
||||
current_app
|
||||
current_app,
|
||||
)
|
||||
from flask.json.tag import JSONTag
|
||||
from flask.cli import AppGroup
|
||||
import uuid
|
||||
import pickle
|
||||
import os
|
||||
import time
|
||||
import random
|
||||
import base64
|
||||
import gevent
|
||||
import click
|
||||
from functools import wraps
|
||||
from concurrent.futures.process import BrokenProcessPool
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
from multiprocessing import Queue
|
||||
from webargs import fields, validate
|
||||
from webargs.flaskparser import use_kwargs
|
||||
|
||||
|
@ -50,11 +44,9 @@ from flask_login import (
|
|||
|
||||
from flask_debugtoolbar import DebugToolbarExtension
|
||||
|
||||
from werkzeug.http import HTTP_STATUS_CODES
|
||||
from sqlalchemy_utils import generic_repr, JSONType, PasswordType, UUIDType
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref
|
||||
from sqlalchemy.types import Float, String, DateTime
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.types import DateTime
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
from .forms import RouteForm, LoginForm, RegisterForm, ChangePasswordForm
|
||||
from .utils import prepare_route, BootsrapRenderer, is_safe_url
|
||||
|
@ -65,22 +57,24 @@ templates = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates"
|
|||
app = Flask(__name__, template_folder=templates)
|
||||
app.config.from_pyfile("config.py")
|
||||
|
||||
executor = Executor(app)
|
||||
db = SQLAlchemy(app)
|
||||
bootstrap = Bootstrap(app)
|
||||
csrf = CSRFProtect(app)
|
||||
nav = Nav(app)
|
||||
login_manager = LoginManager(app)
|
||||
app.executor = executor = Executor(app)
|
||||
app.db = db = SQLAlchemy(app)
|
||||
app.bootstrap = bootstrap = Bootstrap(app)
|
||||
app.csrf = csfr = CSRFProtect(app)
|
||||
app.nav = nav = Nav(app)
|
||||
app.login_manager = login_manager = LoginManager(app)
|
||||
login_manager.login_view = "login"
|
||||
login_manager.session_protection = "strong"
|
||||
admin = Admin(app, name="ED_LRR", template_mode="bootstrap3")
|
||||
app.debug=True
|
||||
toolbar = DebugToolbarExtension(app)
|
||||
app.debug = True
|
||||
app.toolbar = toolbar = DebugToolbarExtension(app)
|
||||
|
||||
|
||||
def wants_json_response():
|
||||
return request.accept_mimetypes['application/json'] >= \
|
||||
request.accept_mimetypes['text/html']
|
||||
return (
|
||||
request.accept_mimetypes["application/json"]
|
||||
>= request.accept_mimetypes["text/html"]
|
||||
)
|
||||
|
||||
|
||||
@app.errorhandler(422)
|
||||
|
@ -89,30 +83,34 @@ def wants_json_response():
|
|||
@app.errorhandler(404)
|
||||
def handle_error(err):
|
||||
if wants_json_response():
|
||||
return jsonify(error=str(err),code=err.code), err.code
|
||||
templates=["error/{}.html".format(err.code),"error/default.html"]
|
||||
return jsonify(error=str(err), code=err.code), err.code
|
||||
templates = ["error/{}.html".format(err.code), "error/default.html"]
|
||||
try:
|
||||
print(dir(err))
|
||||
return render_template(templates,error=err),err.code
|
||||
return render_template(templates, error=err), err.code
|
||||
except TemplateNotFound:
|
||||
return err.get_response()
|
||||
|
||||
|
||||
def role_required(*roles):
|
||||
def wrapper(fn):
|
||||
@wraps(fn)
|
||||
def decorated_view(*args, **kwargs):
|
||||
if not current_user.is_authenticated():
|
||||
return current_app.login_manager.unauthorized()
|
||||
has_role=False
|
||||
user=current_app.login_manager.reload_user()
|
||||
return current_app.login_manager.unauthorized()
|
||||
has_role = False
|
||||
user = current_app.login_manager.reload_user()
|
||||
for role in roles:
|
||||
has_role|=user.has_role(role)
|
||||
has_role |= user.has_role(role)
|
||||
if not has_role:
|
||||
return current_app.login_manager.unauthorized()
|
||||
return fn(*args, **kwargs)
|
||||
|
||||
return decorated_view
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@login_manager.user_loader
|
||||
def load_user(user_name):
|
||||
return User.query.get(user_name)
|
||||
|
@ -120,7 +118,7 @@ def load_user(user_name):
|
|||
|
||||
@login_manager.request_loader
|
||||
def load_user_from_header(header_val):
|
||||
for api_key in [request.args.get('api_key'),request.headers.get('X-API-Key')]:
|
||||
for api_key in [request.args.get("api_key"), request.headers.get("X-API-Key")]:
|
||||
if api_key:
|
||||
user = User.query.filter_by(api_key=api_key).one_or_none()
|
||||
if user:
|
||||
|
@ -130,20 +128,21 @@ def load_user_from_header(header_val):
|
|||
|
||||
|
||||
def left_nav():
|
||||
links=[View("Home", "index"),View("Route", "route"),View("Jobs", "status",job_id=None)]
|
||||
if current_user.has_role('admin') or current_user.has_role('worker_host'):
|
||||
links.insert(2,View("Workers","worker"))
|
||||
return Navbar(
|
||||
"E:D LRR",
|
||||
*links
|
||||
)
|
||||
links = [
|
||||
View("Home", "index"),
|
||||
View("Route", "route"),
|
||||
View("Jobs", "status", job_id=None),
|
||||
]
|
||||
if current_user.has_role("admin") or current_user.has_role("worker_host"):
|
||||
links.insert(2, View("Workers", "worker"))
|
||||
return Navbar("E:D LRR", *links)
|
||||
|
||||
|
||||
def right_nav():
|
||||
links = [View("Login", "login"), View("Register", "register")]
|
||||
if current_user.is_authenticated:
|
||||
links = [View("Change Password", "change_password"), View("Logout", "logout")]
|
||||
if current_user.has_role('admin'):
|
||||
if current_user.has_role("admin"):
|
||||
links = [View("Admin", "admin.index")] + links
|
||||
return Navbar("", *links)
|
||||
|
||||
|
@ -158,16 +157,15 @@ def compute_route(args, kwargs):
|
|||
|
||||
|
||||
class AnonymousUser(AnonymousUserMixin):
|
||||
|
||||
def has_role(self,role):
|
||||
def has_role(self, role):
|
||||
return False
|
||||
|
||||
@property
|
||||
def roles(self):
|
||||
return []
|
||||
|
||||
|
||||
@roles.setter
|
||||
def __set_roles(self,value):
|
||||
def __set_roles(self, value):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
@ -180,52 +178,68 @@ class Worker(db.Model):
|
|||
UUIDType(binary=False, native=False), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
name = db.Column(db.String, unique=True)
|
||||
current_job=db.Column(UUIDType(binary=False, native=False),db.ForeignKey("job.id"), nullable=True,default=None)
|
||||
job = relationship('Job',backref="workers")
|
||||
last_active = db.Column(DateTime, nullable=True,default=None)
|
||||
owner_name = db.Column(
|
||||
db.String, db.ForeignKey("user.name"), nullable=True,index=True
|
||||
current_job = db.Column(
|
||||
UUIDType(binary=False, native=False),
|
||||
db.ForeignKey("job.id"),
|
||||
nullable=True,
|
||||
default=None,
|
||||
)
|
||||
owner = relationship("User",backref="workers")
|
||||
job = relationship("Job", backref="workers")
|
||||
last_active = db.Column(DateTime, nullable=True, default=None)
|
||||
owner_name = db.Column(
|
||||
db.String, db.ForeignKey("user.name"), nullable=True, index=True
|
||||
)
|
||||
owner = relationship("User", backref="workers")
|
||||
|
||||
user_roles = db.Table('user_roles',
|
||||
db.Column('user_name', db.String, db.ForeignKey('user.name'),primary_key=True),
|
||||
db.Column('role_name', db.String, db.ForeignKey('role.name'),primary_key=True)
|
||||
|
||||
user_roles = db.Table(
|
||||
"user_roles",
|
||||
db.Column("user_name", db.String, db.ForeignKey("user.name"), primary_key=True),
|
||||
db.Column("role_name", db.String, db.ForeignKey("role.name"), primary_key=True),
|
||||
)
|
||||
|
||||
class Role(db.Model):
|
||||
name = db.Column(db.String, unique=True,index=True,primary_key=True)
|
||||
|
||||
def __init__(self,name):
|
||||
self.name=name
|
||||
class Role(db.Model):
|
||||
name = db.Column(db.String, unique=True, index=True, primary_key=True)
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class User(db.Model, UserMixin):
|
||||
name = db.Column(db.String, unique=True,index=True,primary_key=True)
|
||||
name = db.Column(db.String, unique=True, index=True, primary_key=True)
|
||||
is_active = db.Column(db.Boolean, default=False)
|
||||
api_key = db.Column(
|
||||
UUIDType(binary=False, native=False), nullable=True, default=uuid.uuid4,index=True
|
||||
UUIDType(binary=False, native=False),
|
||||
nullable=True,
|
||||
default=uuid.uuid4,
|
||||
index=True,
|
||||
)
|
||||
password = db.Column(PasswordType(schemes=["pbkdf2_sha512"], max_length=256))
|
||||
created = db.Column(DateTime, default=datetime.today)
|
||||
|
||||
roles = db.relationship("Role",secondary="user_roles")
|
||||
roles = db.relationship("Role", secondary="user_roles")
|
||||
|
||||
def add_roles(self,roles):
|
||||
def add_roles(self, roles):
|
||||
for role_name in roles:
|
||||
role=Role.query.filter_by(name=role_name).one()
|
||||
if not role in self.roles:
|
||||
role = Role.query.filter_by(name=role_name).one()
|
||||
if role not in self.roles:
|
||||
self.roles.append(role)
|
||||
db.session.commit()
|
||||
|
||||
def has_role(self,role_name):
|
||||
return Role.query.join(User.roles).filter(User.name==self.name,Role.name==role_name).count()>0
|
||||
return ret
|
||||
|
||||
def has_role(self, role_name):
|
||||
return (
|
||||
Role.query.join(User.roles)
|
||||
.filter(User.name == self.name, Role.name == role_name)
|
||||
.count()
|
||||
> 0
|
||||
)
|
||||
|
||||
def reset_api_key(self):
|
||||
self.api_key=uuid,uuid4()
|
||||
self.api_key = uuid.uuid4()
|
||||
db.session.add(self)
|
||||
db.session.comiit()
|
||||
|
||||
|
@ -241,24 +255,23 @@ class Job(db.Model):
|
|||
UUIDType(binary=False, native=False), primary_key=True, default=uuid.uuid4
|
||||
)
|
||||
user_name = db.Column(
|
||||
db.String, db.ForeignKey("user.name"), nullable=True,index=True
|
||||
db.String, db.ForeignKey("user.name"), nullable=True, index=True
|
||||
)
|
||||
func = db.Column(db.String)
|
||||
args = db.Column(JSONType)
|
||||
kwargs = db.Column(JSONType)
|
||||
state = db.Column(JSONType, default={})
|
||||
priority = db.Column(db.Integer, default=0,nullable=True)
|
||||
priority = db.Column(db.Integer, default=0, nullable=True)
|
||||
created = db.Column(DateTime, default=datetime.today)
|
||||
finished = db.Column(DateTime, nullable=True, default=None)
|
||||
started = db.Column(DateTime, nullable=True, default=None)
|
||||
last_update = db.Column(DateTime, nullable=True, default=None)
|
||||
user = relationship("User",backref="jobs")
|
||||
user = relationship("User", backref="jobs")
|
||||
# ============================================================
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.id)
|
||||
|
||||
|
||||
@property
|
||||
def future(self):
|
||||
fut = executor.futures._futures.get(self.id)
|
||||
|
@ -266,20 +279,26 @@ class Job(db.Model):
|
|||
|
||||
@property
|
||||
def sort_key(self):
|
||||
state_priorities={"Queued":0,"Starting":1,"Error":1,"Stalled":1,"Running":1}
|
||||
status_key=state_priorities.get(self.status[1],-1)+1
|
||||
user=1-int(self.user is not None)
|
||||
return (user,-status_key,self.priority,self.created)
|
||||
state_priorities = {
|
||||
"Queued": 0,
|
||||
"Starting": 1,
|
||||
"Error": 1,
|
||||
"Stalled": 1,
|
||||
"Running": 1,
|
||||
}
|
||||
status_key = state_priorities.get(self.status[1], -1) + 1
|
||||
user = 1 - int(self.user is not None)
|
||||
return (user, -status_key, self.priority, self.created)
|
||||
|
||||
@property
|
||||
def age(self):
|
||||
dt=datetime.today()-self.created
|
||||
dt = datetime.today() - self.created
|
||||
return dt - dt % timedelta(seconds=1)
|
||||
|
||||
@classmethod
|
||||
def next(cls):
|
||||
for job in sorted(cls.query.all(),key=lambda v:v.sort_key):
|
||||
if job.status[1] in ['Done']:
|
||||
def get_next(cls):
|
||||
for job in sorted(cls.query.all(), key=lambda v: v.sort_key):
|
||||
if job.status[1] in ["Done"]:
|
||||
continue
|
||||
return job
|
||||
return None
|
||||
|
@ -287,15 +306,15 @@ class Job(db.Model):
|
|||
|
||||
@property
|
||||
def status(self):
|
||||
states=[
|
||||
("primary", "Done"),
|
||||
("danger", "Error"),
|
||||
("info", "Stalled"),
|
||||
("success", "Running"),
|
||||
("secondary", "Starting"),
|
||||
("warning", "Queued")
|
||||
]
|
||||
#return states[self.id.int%len(states)]
|
||||
# [
|
||||
# ("primary", "Done"),
|
||||
# ("danger", "Error"),
|
||||
# ("info", "Stalled"),
|
||||
# ("success", "Running"),
|
||||
# ("secondary", "Starting"),
|
||||
# ("warning", "Queued"),
|
||||
# ]
|
||||
# return states[self.id.int%len(states)]
|
||||
if self.state.get("result"):
|
||||
return ("primary", "Done")
|
||||
if self.state.get("error"):
|
||||
|
@ -391,7 +410,7 @@ class Job(db.Model):
|
|||
).total_seconds()
|
||||
if time_since_last_upd < 5.0:
|
||||
return
|
||||
state = dict()
|
||||
state = {}
|
||||
state.update(self.state)
|
||||
state.update({"progress": cb_state})
|
||||
self.state = state
|
||||
|
@ -403,7 +422,7 @@ class Job(db.Model):
|
|||
|
||||
def done(self, future):
|
||||
print(self.id, "DONE")
|
||||
state = dict()
|
||||
state = {}
|
||||
state.update(self.state)
|
||||
executor.futures.pop(self.id)
|
||||
exc = future.exception()
|
||||
|
@ -420,24 +439,25 @@ class Job(db.Model):
|
|||
|
||||
|
||||
db.create_all()
|
||||
for role in ['admin','user','worker_host']:
|
||||
for role in ["admin", "user", "worker_host"]:
|
||||
if Role.query.filter_by(name=role).one_or_none() is None:
|
||||
db.session.add(Role(role))
|
||||
|
||||
def create_user(name,password,roles,active=False):
|
||||
user=User.query.filter_by(name=name).one_or_none()
|
||||
|
||||
def create_user(name, password, roles, active=False):
|
||||
user = User.query.filter_by(name=name).one_or_none()
|
||||
if user:
|
||||
db.session.delete(user)
|
||||
user=User(name=name,password=password,is_active=active)
|
||||
user = User(name=name, password=password, is_active=active)
|
||||
user.add_roles(roles)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
return user
|
||||
|
||||
create_user('admin','admin',['admin','user'],True)
|
||||
create_user('user','user',['user'],True)
|
||||
create_user('host','host',['user','worker_host'],True)
|
||||
|
||||
# create_user("admin", "admin", ["admin", "user"], True)
|
||||
# create_user("user", "user", ["user"], True)
|
||||
# create_user("host", "host", ["user", "worker_host"], True)
|
||||
|
||||
|
||||
class SQLAView(ModelView):
|
||||
|
@ -449,7 +469,7 @@ class SQLAView(ModelView):
|
|||
column_display_pk = True
|
||||
|
||||
def is_accessible(self):
|
||||
return current_user.is_authenticated and current_user.has_role('admin')
|
||||
return current_user.is_authenticated and current_user.has_role("admin")
|
||||
|
||||
def inaccessible_callback(self, name, **kwargs):
|
||||
return redirect(url_for("login"))
|
||||
|
@ -458,7 +478,7 @@ class SQLAView(ModelView):
|
|||
class UserView(SQLAView):
|
||||
from wtforms import PasswordField
|
||||
|
||||
column_list = ("name", "active", "password", "api_key","roles")
|
||||
column_list = ("name", "active", "password", "api_key", "roles")
|
||||
column_formatters = {
|
||||
"password": lambda view, context, model, name: "",
|
||||
"api_key": lambda view, context, model, name: model.api_key or "",
|
||||
|
@ -469,9 +489,7 @@ class UserView(SQLAView):
|
|||
class JobView(SQLAView):
|
||||
# Job.id,Job.user,Job.func,Job.args,Job.kwargs,Job.state,Job.created,Job.finished,Job.started,Job.last_update
|
||||
column_list = ("id", "status", "user", "created", "started", "finished")
|
||||
column_formatters = {
|
||||
"status": lambda view, context, model, name: model.status[1],
|
||||
}
|
||||
column_formatters = {"status": lambda view, context, model, name: model.status[1]}
|
||||
|
||||
|
||||
class WorkerView(SQLAView):
|
||||
|
@ -485,6 +503,7 @@ class WorkerView(SQLAView):
|
|||
# "status": lambda view, context, model, name: model.status[1],
|
||||
# }
|
||||
|
||||
|
||||
admin.add_view(JobView(Job, db.session))
|
||||
admin.add_view(UserView(User, db.session))
|
||||
admin.add_view(SQLAView(Worker, db.session))
|
||||
|
@ -531,7 +550,7 @@ def api_route(_=None, **args):
|
|||
args["factor"],
|
||||
None,
|
||||
r"D:\devel\rust\ED_LRR\stars.csv",
|
||||
app.config['ROUTE_WORKERS']
|
||||
app.config["ROUTE_WORKERS"],
|
||||
)
|
||||
return jsonify({"id": submit_job(ed_lrr.route, *args)})
|
||||
|
||||
|
@ -544,7 +563,7 @@ def api_status():
|
|||
|
||||
@app.route("/api/whoami")
|
||||
def api_whoami():
|
||||
return jsonify({'name':current_user.name})
|
||||
return jsonify({"name": current_user.name})
|
||||
|
||||
|
||||
@app.route("/api/status/<uuid:job_id>")
|
||||
|
@ -573,21 +592,21 @@ def route():
|
|||
return render_template("form.html", form=form, title="Plot Route")
|
||||
|
||||
|
||||
@app.route("/status/",defaults={'job_id':None})
|
||||
@app.route("/status/", defaults={"job_id": None})
|
||||
@app.route("/status/<uuid:job_id>")
|
||||
@login_required
|
||||
def status(job_id=None):
|
||||
if job_id is not None:
|
||||
job=Job.query.get_or_404(str(job_id))
|
||||
job = Job.query.get_or_404(str(job_id))
|
||||
return render_template("job.html", job=job)
|
||||
return render_template(
|
||||
"status.html", Job=Job, state=request.args.get("state")
|
||||
)
|
||||
return render_template("status.html", Job=Job, state=request.args.get("state"))
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html")
|
||||
|
||||
|
||||
@app.route("/login", methods=["GET", "POST"])
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
|
@ -602,9 +621,9 @@ def login():
|
|||
flash("Account is deactivated!", "warning")
|
||||
return redirect(url_for("login"))
|
||||
login_user(user, remember=form.data["remember"])
|
||||
next = request.args.get('next')
|
||||
next = request.args.get("next")
|
||||
if not is_safe_url(next):
|
||||
next=None
|
||||
next = None
|
||||
return redirect(next or url_for("status"))
|
||||
return render_template("form.html", form=form, title="Login")
|
||||
|
||||
|
@ -614,7 +633,7 @@ def register():
|
|||
form = RegisterForm()
|
||||
if form.validate_on_submit():
|
||||
if User.query.filter_by(name=form.data["username"]).one_or_none() is not None:
|
||||
flash('Username already exists','danger')
|
||||
flash("Username already exists", "danger")
|
||||
return render_template("form.html", form=form, title="Register")
|
||||
user = User()
|
||||
user.name = form.data["username"]
|
||||
|
@ -641,11 +660,13 @@ def change_password():
|
|||
return redirect(url_for("status"))
|
||||
return render_template("form.html", form=form, title="Register")
|
||||
|
||||
|
||||
@app.route("/workers/")
|
||||
@login_required
|
||||
def worker():
|
||||
return render_template("workers.html")
|
||||
|
||||
|
||||
@app.route("/logout")
|
||||
def logout():
|
||||
logout_user()
|
||||
|
@ -654,12 +675,38 @@ def logout():
|
|||
|
||||
@app.before_first_request
|
||||
def resume_jobs():
|
||||
print(Job.next())
|
||||
print("NEXT:", Job.get_next())
|
||||
with app.test_request_context():
|
||||
for job in Job.query.all():
|
||||
if job.status[1] != "Done":
|
||||
print("Restarting {} with state {}".format(job.id, job.status[1]))
|
||||
job.start()
|
||||
|
||||
|
||||
user_cli = AppGroup('user', help="Manage users")
|
||||
job_cli = AppGroup('job', help="Manage Jobs")
|
||||
worker_cli = AppGroup('worker', help="Manage Workers")
|
||||
|
||||
|
||||
@app.cli.command("gevent")
|
||||
def cmd_gevent():
|
||||
return
|
||||
|
||||
|
||||
@user_cli.command("create")
|
||||
@click.argument("name")
|
||||
@click.option("-i", "--inactive", help="Crate account as inactive", is_flag=True, default=False)
|
||||
@click.option("-r", "--role", help="Assign role to account", default=["user"], multiple=True)
|
||||
@click.password_option("-p", "--password", help="Password for user")
|
||||
def cmd_create_user(name, role, password, inactive):
|
||||
"Create a new user"
|
||||
create_user(name, password, role, not inactive)
|
||||
print("User created!")
|
||||
|
||||
|
||||
app.cli.add_command(user_cli)
|
||||
app.cli.add_command(job_cli)
|
||||
app.cli.add_command(worker_cli)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="127.0.0.1", port=3777, debug=True)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
SECRET_KEY = "ED_LRR_WEBAPP"
|
||||
|
@ -8,11 +9,11 @@ SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|||
ROUTE_WORKERS = 0
|
||||
|
||||
EXECUTOR_TYPE = "process"
|
||||
EXECUTOR_MAX_WORKERS = os.cpu_count()-1
|
||||
EXECUTOR_MAX_WORKERS = os.cpu_count() - 1
|
||||
EXECUTOR_FUTURES_MAX_LENGTH = 500
|
||||
|
||||
FLASK_ADMIN_SWATCH = "Darkly"
|
||||
|
||||
DEBUG_TB_TEMPLATE_EDITOR_ENABLED = True
|
||||
|
||||
MAIL_DEFAULT_SENDER = '"ED_LRR Admin" <ed_lrr@gmail.com>'
|
||||
MAIL_DEFAULT_SENDER = '"ED_LRR Admin" <ed_lrr@gmail.com>'
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import (
|
||||
StringField,
|
||||
|
@ -14,6 +15,7 @@ from wtforms.widgets.html5 import NumberInput
|
|||
from wtforms.widgets import TextInput
|
||||
from wtforms.validators import ValidationError
|
||||
|
||||
|
||||
class StringListField(Field):
|
||||
widget = TextInput()
|
||||
|
||||
|
@ -61,7 +63,7 @@ class RouteForm(FlaskForm):
|
|||
default=50,
|
||||
widget=NumberInput(min=0, max=100, step=1),
|
||||
)
|
||||
|
||||
|
||||
priority = FloatField(
|
||||
"Priority (0=max, 100=min)",
|
||||
[validators.NumberRange(0, 100)],
|
||||
|
|
|
@ -20,4 +20,4 @@ table {
|
|||
border: 1px solid #eee;
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
{% block body %}
|
||||
<p>Hello world</p>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -45,4 +45,4 @@
|
|||
{# application content needs to be provided in the app_content block #}
|
||||
{% block app_content %}{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
{% block app_content %}
|
||||
<h1>404 Not Found</h1>
|
||||
<p><a href="{{ url_for('index') }}"><button type="button" class="btn btn-secondary">Back</button></a></p>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -13,4 +13,4 @@
|
|||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
Number of Jobs: {{current_user.jobs|count}}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -128,4 +128,4 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -84,4 +84,4 @@
|
|||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from flask_nav.renderers import Renderer
|
||||
from dominate import tags
|
||||
from urllib.parse import urlparse,urljoin
|
||||
from urllib.parse import urlparse, urljoin
|
||||
from flask import request
|
||||
|
||||
|
||||
def is_safe_url(target):
|
||||
ref_url = urlparse(request.host_url)
|
||||
test_url = urlparse(urljoin(request.host_url, target))
|
||||
return test_url.scheme in ('http', 'https') and \
|
||||
ref_url.netloc == test_url.netloc
|
||||
return test_url.scheme in ("http", "https") and ref_url.netloc == test_url.netloc
|
||||
|
||||
|
||||
def dist(p1, p2):
|
||||
s = 0
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import requests as RQ
|
||||
import _ed_lrr as ed_lrr
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue