diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..7ccaef9 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,23 @@ +image: Visual Studio 2019 +platform: x64 +version: 0.1.{build} +branches: + only: + - pyqt_gui + +environment: + VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat + VCVARSARG: x64 + +install: + - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc + - pip install tox + + +before_build: + - if defined VCVARS call "%VCVARS%" %VCVARSARG% + - conda activate + +test_script: + - tox \ No newline at end of file diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000..7a30eca --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[build] +target-dir = "build\\temp.win-amd64-3.7\\ed_lrr_gui" diff --git a/.gitignore b/.gitignore index 5b0dd33..f0cdfd5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ __pycache__ build *.pdf .history -pip-wheel-metadata \ No newline at end of file +.tox +pip-wheel-metadata diff --git a/LICENSE b/LICENSE index ea8c62e..99ee78e 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in index fe1501c..2f28226 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,3 @@ include rust/Cargo.toml include rust/.cargo/config -recursive-include rust/src * \ No newline at end of file +recursive-include rust/src * diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..d3f6c2a --- /dev/null +++ b/Pipfile @@ -0,0 +1,12 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +ed-lrr-gui = {path = "."} + +[requires] +python_version = "3.7" diff --git a/README.md b/README.md index 3afaad9..2723c76 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# Prerequisites + +- conda (miniconda/anaconda) +- Visual Studio 2019 +- nightly rust compiler (`x86_64-pc-windows-msvc`) + # Testing ```bash @@ -14,7 +20,7 @@ rs_gui_test conda create -n ed_lrr_gui_env python=3 conda activate ed_lrr_gui_env python build_gui.py -pip install setuptools_rust +pip install setuptools_rust pyinstaller pip install . python setup.py build python setup.py bdist_wheel @@ -38,4 +44,4 @@ cd .. # TODO - integrate callbacks into the GUI: WIP - - QTimer pulls from queue updates UI (every 100ms) \ No newline at end of file + - QTimer pulls from queue updates UI (every 100ms) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..7ccaef9 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,23 @@ +image: Visual Studio 2019 +platform: x64 +version: 0.1.{build} +branches: + only: + - pyqt_gui + +environment: + VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat + VCVARSARG: x64 + +install: + - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + - rustup-init -yv --default-toolchain nightly --default-host x86_64-pc-windows-msvc + - pip install tox + + +before_build: + - if defined VCVARS call "%VCVARS%" %VCVARSARG% + - conda activate + +test_script: + - tox \ No newline at end of file diff --git a/build.bat b/build.bat index 9487f53..7f064ec 100644 --- a/build.bat +++ b/build.bat @@ -1,11 +1,10 @@ -rm -rf build dist *.egg-info exe -python build_gui.py -pip uninstall -y ed_lrr_gui -pip install -I . setuptools_rust -python setup.py build -python setup.py bdist_wheel -python setup.py sdist -mkdir exe -cd exe -pyinstaller --noupx --noconsole --key="ED_LRR_GUI" --name ED_LRR_GUI ..\ed_lrr_gui\__main__.py -cd .. \ No newline at end of file +@echo off +:: TODO: convert to python script +:: set up new conda env, install packages, build, remove conda env +call conda create -y -n ed_lrr python=3 pycrypto || exit /b 1 +call conda activate ed_lrr || exit /b 1 +call conda install -y -c conda-forge nuitka +vcvars x64 +python build.py +call conda deactivate || exit /b 1 +call conda env remove -n ed_lrr || exit /b 1 \ No newline at end of file diff --git a/build.py b/build.py new file mode 100644 index 0000000..8bce8ab --- /dev/null +++ b/build.py @@ -0,0 +1,66 @@ +import subprocess as SP +from glob import glob +import os +import shutil +import pkg_resources as pkg +from contextlib import contextmanager + +@contextmanager +def in_dir(name,remove=False): + pwd=os.getcwd() + if os.path.isdir(name): + shutil.rmtree(name) + os.makedirs(name) + os.chdir(name) + yield + os.chdir(pwd) + if remove: + shutil.rmtree(name) + +SP.check_call(["pip", "install", "PyQt5"]) + +ui_path = os.path.dirname(os.path.abspath(__file__)) +for root, folders, files in os.walk(ui_path): + for file in files: + file = os.path.join(root, file) + outfile, ext = os.path.splitext(file) + if ext == ".ui": + outfile = outfile + ".py" + print(os.path.basename(file), "->", os.path.basename(outfile)) + SP.check_call(["pyuic5", "--from-imports", "-o", outfile, file]) + +SP.check_call(["pip", "install", ".[dev]"]) +main_py=os.path.abspath("ed_lrr_gui\__main__.py") +with in_dir("exe"): + with in_dir("pyinstaller"): + SP.check_call( + [ + "pyinstaller", + "--clean", + "--noupx", + "-c", + '--key="ED_LRR_GUI"', + "--name", + "ED_LRR", + main_py, + ] + ) + with in_dir("nuitka"): + SP.check_call( + [ + "python", + "-m", + "nuitka", + "--plugin-enable=multiprocessing", + "--plugin-enable=qt-plugins", + "--standalone", + "--follow-imports", + main_py, + ] + ) + + +# with in_dir("installer"): +# shutil.rmtree("Output") +# SP.check_call(["iscc", "/QP", "ED_LRR.iss"]) + diff --git a/clean.bat b/clean.bat index 098a107..20a9545 100644 --- a/clean.bat +++ b/clean.bat @@ -2,4 +2,4 @@ rm -rfv _*.pyd *.egg-info pip-wheel-metadata dist exe build __pycache__ cd rust cargo clean cargo clean --release -cd .. \ No newline at end of file +cd .. diff --git a/docs/.vscode/settings.json b/docs/.vscode/settings.json index e674f84..f02fbe4 100644 --- a/docs/.vscode/settings.json +++ b/docs/.vscode/settings.json @@ -8,4 +8,4 @@ "latex", "plaintext" ] -} \ No newline at end of file +} diff --git a/docs/Makefile b/docs/Makefile index 60a308c..f0dbc9f 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -45,4 +45,4 @@ watch: watchexec -w src -w data -w filters -w Makefile make all clean: - -rm $(PDFS) $(IMGS) \ No newline at end of file + -rm $(PDFS) $(IMGS) diff --git a/docs/filters/multifilter.py b/docs/filters/multifilter.py index 2cc9ff0..3ae005c 100644 --- a/docs/filters/multifilter.py +++ b/docs/filters/multifilter.py @@ -1,18 +1,19 @@ -from panflute import * -import tempfile -import sys -from jinja2 import Template, Environment, PackageLoader, select_autoescape import contextlib -import io -import hashlib -from dateutil.parser import parse as dateparse -from functools import partial -import subprocess as SP -import panflute as pf -import os import csv import datetime +import hashlib +import io +import os import re +import subprocess as SP +import sys +import tempfile +from functools import partial + +import panflute as pf +from dateutil.parser import parse as dateparse +from jinja2 import Environment, PackageLoader, Template, select_autoescape +from panflute import * def remove_pound(elem, doc): @@ -29,10 +30,10 @@ def fix_color(elem, doc): def update_date(elem, doc): if type(elem) == MetaMap: - datefmt = doc.get_metadata('datefmt', "%Y-%m-%d") + datefmt = doc.get_metadata("datefmt", "%Y-%m-%d") today = datetime.date.today().strftime(datefmt) - date = dateparse(doc.get_metadata('date', today)).date() - elem['date'] = MetaInlines(Str(date.strftime(datefmt))) + date = dateparse(doc.get_metadata("date", today)).date() + elem["date"] = MetaInlines(Str(date.strftime(datefmt))) return elem @@ -42,8 +43,7 @@ def csv_table(elem, doc): ext = os.path.splitext(elem.url)[1][1:] if ext == "csv": caption = elem.content - has_header = elem.attributes.get( - 'has-header', "false").lower() == "true" + has_header = elem.attributes.get("has-header", "false").lower() == "true" with open(elem.url) as f: reader = csv.reader(f) body = [] @@ -62,7 +62,12 @@ def code_refs(elem, doc): label = label.text filename = re.findall(r"^\[@lst:(.*)\]$", label) or [None] if filename[0] in doc.inc_files: - return [RawInline("\\hyperref[{}]{{{}}}".format(filename[0], filename[0]), format="tex")] + return [ + RawInline( + "\\hyperref[{}]{{{}}}".format(filename[0], filename[0]), + format="tex", + ) + ] def include_code(elem, doc): @@ -71,9 +76,8 @@ def include_code(elem, doc): filepath = elem.attributes.pop("include") filename = os.path.split(filepath)[-1] try: - elem.text += elem.text + \ - open(filepath, encoding="utf-8").read() - elem.attributes['caption'] = filename + elem.text += elem.text + open(filepath, encoding="utf-8").read() + elem.attributes["caption"] = filename doc.inc_files.append(filename) except Exception as e: elem.text += "Error: {}".format(e) @@ -92,28 +96,26 @@ def jinja_py_filt(doc, file): env = {} code = open(file, encoding="utf-8").read() exec(code, env) - return env['main'](doc) + return env["main"](doc) def prepare(doc): doc.inc_files = [] doc.env = Environment() doc.pyenv = {} - filters = {'py': partial(jinja_py_filt, doc)} + filters = {"py": partial(jinja_py_filt, doc)} doc.env.filters.update(filters) def process_templates(elem, doc): if type(elem) == CodeBlock: if elem.classes == ["@"]: - args = {'meta': doc.get_metadata()} + args = {"meta": doc.get_metadata()} return convert_text(doc.env.from_string(elem.text).render(args)) def yaml_filt(elem, doc): - tags = { - 'eval': py_eval, - } + tags = {"eval": py_eval} return yaml_filter(elem, doc, tags=tags, strict_yaml=True) @@ -138,8 +140,16 @@ def checkboxes(elem, doc): def main(doc=None): - f = [process_templates, update_date, csv_table, include_code, - fix_color, code_refs, yaml_filt, checkboxes] + f = [ + process_templates, + update_date, + csv_table, + include_code, + fix_color, + code_refs, + yaml_filt, + checkboxes, + ] return run_filters(f, prepare=prepare, doc=doc) diff --git a/docs/src/img_out.py b/docs/src/img_out.py index 7179b78..deb32bc 100644 --- a/docs/src/img_out.py +++ b/docs/src/img_out.py @@ -1,8 +1,9 @@ -import sys -import pylab as PL -import numpy as np -from scipy.spatial.ckdtree import cKDTree import heapq +import sys + +import numpy as np +import pylab as PL +from scipy.spatial.ckdtree import cKDTree exit() diff --git a/ed_lrr_gui/__init__.py b/ed_lrr_gui/__init__.py index 9bce23f..ce16d39 100644 --- a/ed_lrr_gui/__init__.py +++ b/ed_lrr_gui/__init__.py @@ -1,4 +1,4 @@ from _ed_lrr import * -from . import gui -from .router import Router + from .preprocess import Preprocessor +from .router import Router diff --git a/ed_lrr_gui/__main__.py b/ed_lrr_gui/__main__.py index 153f408..be94950 100644 --- a/ed_lrr_gui/__main__.py +++ b/ed_lrr_gui/__main__.py @@ -1,562 +1,111 @@ import sys -import os -import requests as RQ -from datetime import datetime, timedelta -from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QObject -from PyQt5.QtWidgets import ( - QMainWindow, - QApplication, - QFileDialog, - QProgressDialog, - QTreeWidgetItem, - QAction, - QMessageBox, -) -from urllib.request import Request, urlopen -import gzip -import pathlib -from PyQt5.QtGui import QPalette, QColor -import ed_lrr_gui -import ed_lrr_gui.config as cfg -from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR -from ed_lrr_gui import Router, Preprocessor import multiprocessing as MP import queue -import csv -import _ed_lrr +import ctypes +from math import floor +import click +from click_default_group import DefaultGroup +import requests as RQ +from ed_lrr_gui import Router +from ed_lrr_gui import Preprocessor +import ed_lrr_gui.gui as ED_LRR_GUI +CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) - -def sizeof_fmt(num, suffix="B"): - for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: - if abs(num) < 1024.0: - return "{:.02f}{}{}".format(num, unit, suffix) - num /= 1024.0 - return "{:.02f}{}{}".format(num, "Yi", suffix) - - -def t_round(dt): - return dt - dt % timedelta(seconds=1) - - -class ProgressDialog(QProgressDialog): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.setWindowModality(Qt.WindowModal) - - -class Job(QObject): - progress = pyqtSignal("PyQt_PyObject") - - def __init__(self, app, cls, *args, build_progress=None, **kwargs): - super().__init__() - self.job = cls(*args, **kwargs) - self.timer = QTimer(app) - self.app = app - self.timer.timeout.connect(self.interval) - self.timer.start(100) - self.last_val = None - self.build_progress = build_progress - self.progress_dialog = None - self.state = {} - - def start(self): - """ - if self.diag_prog is None: - self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) - if self.dl_thread: - self.diag_prog.canceled.connect(self.dl_canceled) - self.diag_prog.show() - t_elapsed = datetime.today() - self.dl_started - rate = args["done"] / t_elapsed.total_seconds() - remaining = (args["size"] - args["done"]) / rate - rate = round(rate, 2) - # print(rate, remaining) - try: - t_rem = timedelta(seconds=remaining) - except OverflowError: - t_rem = "-" - msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( - filename, - sizeof_fmt(args["done"]), - sizeof_fmt(args["size"]), - sizeof_fmt(rate), - t_round(t_elapsed), - t_round(t_rem), - ) - self.diag_prog.setLabelText(msg) - self.diag_prog.setWindowTitle("Downloading EDSM Dumps") - self.diag_prog.setValue((args["done"] * 1000) // args["size"]) - """ - self.started = datetime.today() - if self.build_progress: - self.progress_dialog = ProgressDialog("", "Cancel", 0, 1000, self.app) - self.progress_dialog.canceled.connect(self.cancel) - self.progress_dialog.show() - self.progress.connect(self.__build_progress) - else: - self.progress.connect( - lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs) - ) - return self.job.start() - - def __build_progress(self, *args, **kwargs): - kwargs["self"] = self - return self.build_progress(*args, **kwargs) - - def cancel(self): - self.job.terminate() - self.job = None - - def done(self): - return (self.job.is_alive() == False) and (self.job.queue.empty()) - - def interval(self): - while True: - try: - res = self.job.queue.get(True, 0.1) - except queue.Empty: - return - if res == self.last_val: - continue - self.state.update(res) - self.progress.emit(self.state) - self.last_val = res - - -class DownloadThread(QThread): - progress = pyqtSignal("PyQt_PyObject") - - def __init__(self, systems_url, systems_file, bodies_url, bodies_file): - super().__init__() - self.systems_url = systems_url - self.systems_file = systems_file - self.bodies_url = bodies_url - self.bodies_file = bodies_file - self.running = True - - def __del__(self): - self.wait() - - def stop(self): - self.running = False - - def run(self): - dl_jobs = [ - (self.systems_url, self.systems_file), - (self.bodies_url, self.bodies_file), - ] - for url, dest in dl_jobs: - outfile = url.split("/")[-1] - size = RQ.head(url, headers={"Accept-Encoding": "None"}) - size.raise_for_status() - size = int(size.headers.get("Content-Length", 0)) - with open(dest, "wb") as of: - resp = RQ.get(url, stream=True) - for chunk in resp.iter_content(1024 * 1024): - of.write(chunk) - self.progress.emit( - {"done": of.tell(), "size": size, "outfile": outfile} - ) - if not self.running: - return - - -class App(QApplication): - def __init__(self): - super().__init__(sys.argv) - self.setStyle("Fusion") - self.setup_styles() - - def set_style(self, style): - print("LOAD:", style) - self.setPalette(self.styles[style]) - - def setup_styles(self): - self.styles = {} - styles = { - "Dark": { - "Window": QColor(53, 53, 53), - "WindowText": Qt.white, - "Base": QColor(15, 15, 15), - "AlternateBase": QColor(53, 53, 53), - "ToolTipBase": Qt.white, - "ToolTipText": Qt.white, - "Text": Qt.white, - "Button": QColor(53, 53, 53), - "ButtonText": Qt.white, - "BrightText": Qt.red, - "Highlight": QColor(255, 128, 0), - "HighlightedText": Qt.black, - } - } - for style, colors in styles.items(): - palette = QPalette() - for entry, color in colors.items(): - palette.setColor(getattr(QPalette, entry), color) - if color == Qt.darkGray: - palette.setColor( - QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) - ) - else: - palette.setColor( - QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray - ) - self.styles[style] = palette - self.styles["Light"] = self.style().standardPalette() - - -class ED_LRR(Ui_ED_LRR): - dl_thread = None - diag_prog = None - dl_started = None - system_found = pyqtSignal("PyQt_PyObject") - - def __init__(self): - super().__init__() - self.config = cfg.load() - self.jobs = {} - - def start_job(self, cls, *args, **kwargs): - print("START JOB:", cls, args, kwargs) - name = cls.__name__ - if name in self.jobs and self.jobs[name].done(): - del self.jobs[name] - if not name in self.jobs: - self.jobs[name] = Job(self.app, cls, *args, **kwargs) - self.jobs[name].start() - - def get_open_file(self, filetypes, callback=None): - fileName, _ = QFileDialog.getOpenFileName( - self.main_window, - "Open file", - str(cfg.data_dir), - filetypes, - options=QFileDialog.DontUseNativeDialog, - ) - if callback: - return callback(fileName) - return fileName - - def get_save_file(self, filetypes, callback=None): - fileName, _ = QFileDialog.getSaveFileName( - self.main_window, - "Save file", - str(cfg.data_dir), - filetypes, - options=QFileDialog.DontUseNativeDialog, - ) - if callback: - return callback(fileName) - return fileName - - def set_sys_lst(self, path): - if path not in self.config.history_out_path: - self.config.history_out_path.append(path) - self.inp_sys_lst.addItem(path) - self.inp_out_pp.addItem(path) - self.inp_sys_lst.setCurrentText(path) - self.inp_out_pp.setCurrentText(path) - - def set_bodies_file(self, path): - if path not in self.config.history_bodies_path: - self.config.history_bodies_path.append(path) - self.inp_bodies_pp.addItem(path) - - def set_systems_file(self, path): - if path not in self.config.history_systems_path: - self.config.history_systems_path.append(path) - self.inp_systems_pp.addItem(path) - - def update_dropdowns(self): +@click.group(invoke_without_command=True,context_settings=CONTEXT_SETTINGS) +@click.pass_context +def main(ctx): + "Elite: Dangerous long range router, command line interface" + if ctx.invoked_subcommand is None: + ctx.invoke(gui) return + return - def log(self, *args): - t = datetime.today() - msg_t = "[{}] {}".format(t, str.format(*args)) - self.txt_log.append(msg_t) +@main.command() +@click.option("--debug",help="Debug print",is_flag=True) +def gui(debug): + "Run the ED LRR GUI (default)" + if not debug: + ctypes.windll.kernel32.FreeConsole() + sys.stdin=open("NUL","rt") + sys.stdout=open("NUL","wt") + sys.stderr=open("NUL","wt") + sys.exit(ED_LRR_GUI.main()) - def set_comp_mode(self, _): - if self.rd_comp.isChecked(): - comp_mode = "Compute Route" - self.btn_add.setText("Add") - if self.rd_precomp.isChecked(): - comp_mode = "Precompute Graph" - self.btn_add.setText("Select") - self.log("COMP_MODE", comp_mode) - self.lst_sys.setEnabled(self.rd_comp.isChecked()) - self.btn_rm.setEnabled(self.rd_comp.isChecked()) - self.cmb_mode.setEnabled(self.rd_comp.isChecked()) - self.chk_permute.setEnabled(self.rd_comp.isChecked()) - self.lbl_keep.setEnabled(self.rd_comp.isChecked()) - self.lbl_mode.setEnabled(self.rd_comp.isChecked()) - self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) - self.chk_permute_keep_last.setEnabled(self.rd_comp.isChecked()) - self.set_route_mode(self.rd_precomp.isChecked() or None) +@main.command() +@click.option("--url","-u",help="Base URL",default="https://www.edsm.net/dump/",show_default=True) +@click.option("--systems","-s",help="Target path for systemsWithCoordinates.json",default="systemsWithCoordinates.json",show_default=True) +@click.option("--bodies","-b",help="Target path for bodies.json",default="bodies.json",show_default=True) +def download(*args,**kwargs): + "Download EDSM dumps" + print("Download:",args,kwargs) + click.pause() - def set_route_mode(self, mode=None): - if mode == None: - mode = self.cmb_mode.currentText() - self.lbl_greedyness.setEnabled(mode == "A*-Search") - self.sld_greedyness.setEnabled(mode == "A*-Search") +@main.command() +def preprocess(*args,**kwargs): + "Preprocess EDSM dumps" + print("PreProcess:",ctx,args,kwargs) + click.pause() - def set_greedyness(self, value): - self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) - @property - def systems(self): - ret = [] - for n in range(self.lst_sys.topLevelItemCount()): - ret.append(self.sys_to_dict(n)) - return ret - - def sys_to_dict(self, n): - header = [ - self.lst_sys.headerItem().data(c, 0) - for c in range(self.lst_sys.headerItem().columnCount()) - ] - system = [ - self.lst_sys.topLevelItem(n).data(c, 0) - for c in range(self.lst_sys.topLevelItem(n).columnCount()) - ] - ret = dict(zip(header, system)) - ret["id"] = getattr(self.lst_sys.topLevelItem(n), "__id__", None) - ret.pop(None, None) - return ret - - def error(self, msg): - QMessageBox.critical(self.main_window, "ERROR!", msg) - - def get_sys_list(self): - if not self.inp_sys_lst.currentText(): - self.error("System list is required!") - return - path = pathlib.Path(self.inp_sys_lst.currentText()) - if not path.exists(): - self.error("System list does not exist, run download and preprocess first!") - return - return path - - def run(self): - if not all(s["Type"] for s in self.systems): - self.error('Not all systens have been resolved, please click "Search All"') - return - print(self.systems) - systems = [str(s["id"]) for s in self.systems] - jump_range = self.sb_range.value() - mode = self.cmb_mode.currentText() - primary = self.chk_primary.isChecked() - keep_first = self.chk_permute_keep_first.isChecked() - keep_last = self.chk_permute_keep_last.isChecked() - permute = self.chk_permute.isChecked() - greedyness = ( - self.sld_greedyness.value() / 100 - if self.sld_greedyness.isEnabled() - else None - ) - path = self.get_sys_list() - if path is None: - return - precomp = path.with_suffix(".idx") - path = str(path) - if not precomp.exists(): - precomp = None - else: - precomp = str(precomp) - mode = { - "Breadth-First Search": "bfs", - "A*-Search": "astar", - "Greedy-Search": "greedy", - }[mode] - print( - systems, - jump_range, - mode, - primary, - permute, - (keep_first, keep_last), - greedyness, - path, - precomp, - ) - self.start_job( - Router, - systems, - jump_range, - 0.1, - mode, - primary, - permute, - keep_first, - keep_last, - greedyness, - precomp, - path, - ) - - def find_sys_by_names(self, names): - t_s = datetime.today() - if not self.get_sys_list(): - return None - ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText()) - print("Took:", datetime.today() - t_s) - return ret - - def resolve_systems(self): - names = [] - for n in range(self.lst_sys.topLevelItemCount()): - names.append(self.sys_to_dict(n)["Name"]) - systems = self.find_sys_by_names(names) - if systems is None: - return - for i, name in enumerate(names): - _, system = systems[name] - self.lst_sys.topLevelItem(i).setData(0, 0, system["system"]) - self.lst_sys.topLevelItem(i).setData(1, 0, system["star_type"]) - self.lst_sys.topLevelItem(i).__id__ = system["id"] - # diff, item = self.find_sys_by_name(name) - # print("Found", (diff, item)) - - def add_system(self): - name = self.inp_sys.text() - item = QTreeWidgetItem(self.lst_sys, [name, None]) - item.resolved = False - item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) - - def remove_system(self): - root = self.lst_sys.invisibleRootItem() - for item in self.lst_sys.selectedItems(): - root.removeChild(item) - - def dl_canceled(self): - if self.dl_thread: - print("Cancel!") +@main.command() +@click.option("--path","-i",required=True,metavar="",help="Path to stars.csv",default="./stars.csv",type=click.Path(exists=True,dir_okay=False),show_default=True ) +@click.option("--precomp_file","-pf",metavar="",help="Precomputed routing graph to use",type=click.Path(exists=True,dir_okay=False)) +@click.option("--range","-r",required=True,metavar="",help="Jump range (Ly)",type=click.FloatRange(min=0)) +@click.option("--prune","-d",default=(0,0),metavar=" ",help="Prune search branches",nargs=2,type=click.Tuple([click.IntRange(min=0),click.FloatRange(min=0)])) +@click.option("--permute","-p",type=click.Choice(["all","keep_first","keep_last","keep_both"]),default=None,help="Permute hops to find shortest route",show_default=True) +@click.option("--primary","-ps",is_flag=True,default=False,help="Only route through primary stars") +@click.option("--factor","-g",metavar="",default=0.5,help="Greedyness factor for A-Star",show_default=True) +@click.option("--mode","-m",default="bfs",help="Search mode",type=click.Choice(["bfs","a-star","greedy"]),show_default=True) +@click.argument('systems',nargs=-1) +def route(**kwargs): + "Compute a route" + if kwargs['prune']==(0,0): + kwargs['prune']=None + def to_string(state): + if state: + return "[{}] {}".format(state['depth'],state['system']) + keep_first,keep_last={ + "all":(False,False), + "keep_first":(True,False), + "keep_last":(False,True), + "keep_both":(True,True), + None: (False,False) + }[kwargs['permute']] + args=[kwargs['systems'],kwargs['range'],kwargs['prune'],kwargs['mode'],kwargs['primary'],kwargs['permute']!=None,keep_first,keep_last,kwargs['factor'],None,kwargs['path']] + with click.progressbar(length=100,label="Computing route",show_percent=True,item_show_func=to_string,width=50) as pbar: + router=Router(*args) + router.start() + state={} + pstate={} + while not (router.queue.empty() and router.is_alive()==False): try: - self.dl_thread.progress.disconnect() - except TypeError: + event = router.queue.get(True,0.1) + state.update(event) + if state!=pstate: + pbar.current_item=state.get("status") + if pbar.current_item: + pbar.pos=floor(pbar.current_item["prc_done"]*10)/10 + pbar.update(0) + pstate=state + except queue.Empty: pass - self.dl_thread.stop() - self.dl_thread.wait() - self.diag_prog.close() - self.dl_thread = None - self.diag_prog = None - self.dl_started = None + pbar.pos=100 + pbar.update(0) + print(state.get("result")) + print("DONE!") - def handle_dl_progress(self, args): - filename = os.path.split(args["outfile"])[-1] - if self.diag_prog is None: - self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) - if self.dl_thread: - self.diag_prog.canceled.connect(self.dl_canceled) - self.diag_prog.show() - t_elapsed = datetime.today() - self.dl_started - rate = args["done"] / t_elapsed.total_seconds() - remaining = (args["size"] - args["done"]) / rate - rate = round(rate, 2) - # print(rate, remaining) - try: - t_rem = timedelta(seconds=remaining) - except OverflowError: - t_rem = "-" - msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( - filename, - sizeof_fmt(args["done"]), - sizeof_fmt(args["size"]), - sizeof_fmt(rate), - t_round(t_elapsed), - t_round(t_rem), - ) - self.diag_prog.setLabelText(msg) - self.diag_prog.setWindowTitle("Downloading EDSM Dumps") - self.diag_prog.setValue((args["done"] * 1000) // args["size"]) - - def run_download(self): - if self.dl_thread: - return - self.dl_started = datetime.today() - self.dl_thread = DownloadThread( - self.inp_systems_dl.currentText(), - self.inp_systems_dest_dl.currentText(), - self.inp_bodies_dl.currentText(), - self.inp_bodies_dest_dl.currentText(), - ) - self.dl_thread.progress.connect(self.handle_dl_progress) - self.dl_thread.start() - print(".") - - def update_permute_chk(self, state): - self.chk_permute_keep_first.setEnabled(state) - self.chk_permute_keep_last.setEnabled(state) - self.lbl_keep.setEnabled(state) - - def setup_signals(self): - self.btn_download.clicked.connect(self.run_download) - self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") - self.inp_bodies_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\b.json") - self.set_greedyness(self.sld_greedyness.value()) - self.cmb_mode.currentTextChanged.connect(self.set_route_mode) - self.rd_comp.toggled.connect(self.set_comp_mode) - self.rd_precomp.toggled.connect(self.set_comp_mode) - self.sld_greedyness.valueChanged.connect(self.set_greedyness) - self.btn_go.clicked.connect(self.run) - self.btn_add.clicked.connect(self.add_system) - self.btn_rm.clicked.connect(self.remove_system) - self.chk_permute.stateChanged.connect(self.update_permute_chk) - self.btn_search.clicked.connect(self.resolve_systems) - self.btn_out_browse_pp.clicked.connect( - lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) - ) - self.btn_sys_lst_browse.clicked.connect( - lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst) - ) - - self.btn_bodies_browse_pp.clicked.connect( - lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file) - ) - self.btn_bodies_dest_browse_dl.clicked.connect( - lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file) - ) - self.btn_systems_browse_pp.clicked.connect( - lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file) - ) - self.btn_systems_dest_browse_dl.clicked.connect( - lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) - ) - - def handle_close(self): - cfg.write(self.config) - print("BYEEEEEE!") - - def setup_styles(self, win, app): - for name in app.styles: - action = QAction(app) - action.setObjectName("action_load_style_" + name) - action.setText(name) - action.triggered.connect(lambda _, name=name: app.set_style(name)) - self.menuStyle.addAction(action) - - def setupUi(self, MainWindow, app): - super().setupUi(MainWindow) - self.update_dropdowns() - self.main_window = MainWindow - self.app = app - self.setup_signals() - self.lst_sys.setHeaderLabels(["Name", "Type"]) - self.set_route_mode() - self.update_permute_chk(self.chk_permute.isChecked()) - self.setup_styles(MainWindow, app) +@main.command() +@click.option("--path","-i",required=True,help="Path to stars.csv",default="./stars.csv",type=click.Path(exists=True,dir_okay=False),show_default=True ) +@click.option("--precomp_file","-pc",help="Precomputed routing graph to use",type=click.Path(exists=True,dir_okay=False)) +@click.option("--range","-r",required=True,help="Jump range (Ly)",type=click.FloatRange(min=0)) +@click.option("--primary","-ps",help="Only route through primary stars") +@click.option("--output","-o",required=True,help="Output path",default="./stars.idx",type=click.Path(exists=False,dir_okay=False),show_default=True ) +@click.argument('systems',nargs=-1) +def precompute(*args,**kwargs): + "Precompute routing graph" + print("PreComp:",ctx,args,kwargs) -def main(): - app = App() - MainWindow = QMainWindow() - ui = ED_LRR() - ui.setupUi(MainWindow, app) - MainWindow.show() - ret = app.exec_() - ui.handle_close() - exit(ret) - - -if __name__ == "__main__": +if __name__ == '__main__': MP.freeze_support() - main() + main() \ No newline at end of file diff --git a/ed_lrr_gui/config.py b/ed_lrr_gui/config.py index 3e748b7..9720f2d 100644 --- a/ed_lrr_gui/config.py +++ b/ed_lrr_gui/config.py @@ -1,7 +1,8 @@ import pathlib +from collections import namedtuple + import appdirs import yaml -from collections import namedtuple config_dir = pathlib.Path(appdirs.user_config_dir("ED_LRR")) config_dir.mkdir(parents=True, exist_ok=True) diff --git a/ed_lrr_gui/gui/__init__.py b/ed_lrr_gui/gui/__init__.py index e69de29..b668da9 100644 --- a/ed_lrr_gui/gui/__init__.py +++ b/ed_lrr_gui/gui/__init__.py @@ -0,0 +1 @@ +from .main import main \ No newline at end of file diff --git a/ed_lrr_gui/gui/ed_lrr.py b/ed_lrr_gui/gui/ed_lrr.py index c33b639..0ce8074 100644 --- a/ed_lrr_gui/gui/ed_lrr.py +++ b/ed_lrr_gui/gui/ed_lrr.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'D:\devel\rust\ed_lrr_gui\ed_lrr_gui\gui\ed_lrr.ui' # -# Created by: PyQt5 UI code generator 5.13.0 +# Created by: PyQt5 UI code generator 5.13.1 # # WARNING! All changes made in this file will be lost! diff --git a/ed_lrr_gui/gui/main.py b/ed_lrr_gui/gui/main.py new file mode 100644 index 0000000..af409d7 --- /dev/null +++ b/ed_lrr_gui/gui/main.py @@ -0,0 +1,546 @@ +import csv +import gzip +import multiprocessing as MP +import os +import pathlib +import queue +import sys +from sys import exit +from datetime import datetime, timedelta +from urllib.request import Request, urlopen + +import _ed_lrr +import ed_lrr_gui +import ed_lrr_gui.config as cfg +import requests as RQ +from ed_lrr_gui import Preprocessor, Router +from ed_lrr_gui.gui.ed_lrr import Ui_ED_LRR +from PyQt5.QtCore import QObject, Qt, QThread, QTimer, pyqtSignal +from PyQt5.QtGui import QColor, QPalette,QIcon +from PyQt5.QtWidgets import ( + QAction, + QApplication, + QFileDialog, + QMainWindow, + QMessageBox, + QProgressDialog, + QTreeWidgetItem, +) + + +def sizeof_fmt(num, suffix="B"): + for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: + if abs(num) < 1024.0: + return "{:.02f}{}{}".format(num, unit, suffix) + num /= 1024.0 + return "{:.02f}{}{}".format(num, "Yi", suffix) + + +def t_round(dt): + return dt - dt % timedelta(seconds=1) + + +class ProgressDialog(QProgressDialog): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setWindowModality(Qt.WindowModal) + + +class Job(QObject): + progress = pyqtSignal("PyQt_PyObject") + + def __init__(self, app, main_window, cls, *args, **kwargs): + super().__init__() + self.job = cls(*args, **kwargs) + self.timer = QTimer(app) + self.app = app + self.main_window = main_window + self.timer.timeout.connect(self.interval) + self.timer.start(100) + self.last_val = None + self.progress_dialog = None + self.handle_progess = None + self.state = {} + + def setup_progress(self, handle_progess): + self.progress.connect( + lambda *args, **kwargs: handle_progess(self, *args, **kwargs) + ) + + def start(self): + if self.progress_dialog is None: + self.progress.connect( + lambda *args, **kwargs: print("PROGRESS:", *args, **kwargs) + ) + self.started = datetime.today() + return self.job.start() + + def cancel(self): + self.job.terminate() + self.job = None + + def done(self): + return (self.job.is_alive() == False) and (self.job.queue.empty()) + + def interval(self): + while True: + try: + res = self.job.queue.get(True, 0.1) + except queue.Empty: + return + if res == self.last_val: + continue + self.state.update(res) + self.progress.emit(self.state) + self.last_val = res + + +class DownloadThread(QThread): + progress = pyqtSignal("PyQt_PyObject") + + def __init__(self, systems_url, systems_file, bodies_url, bodies_file): + super().__init__() + self.systems_url = systems_url + self.systems_file = systems_file + self.bodies_url = bodies_url + self.bodies_file = bodies_file + self.running = True + + def __del__(self): + self.wait() + + def stop(self): + self.running = False + + def run(self): + dl_jobs = [ + (self.systems_url, self.systems_file), + (self.bodies_url, self.bodies_file), + ] + for url, dest in dl_jobs: + outfile = url.split("/")[-1] + size = RQ.head(url, headers={"Accept-Encoding": "None"}) + size.raise_for_status() + size = int(size.headers.get("Content-Length", 0)) + with open(dest, "wb") as of: + resp = RQ.get(url, stream=True) + for chunk in resp.iter_content(1024 * 1024): + of.write(chunk) + self.progress.emit( + {"done": of.tell(), "size": size, "outfile": outfile} + ) + if not self.running: + return + + +class App(QApplication): + def __init__(self): + super().__init__(sys.argv) + self.setStyle("Fusion") + self.setup_styles() + + def set_style(self, style): + print("LOAD:", style) + self.setPalette(self.styles[style]) + + def setup_styles(self): + self.styles = {} + styles = { + "Dark": { + "Window": QColor(53, 53, 53), + "WindowText": Qt.white, + "Base": QColor(15, 15, 15), + "AlternateBase": QColor(53, 53, 53), + "ToolTipBase": Qt.white, + "ToolTipText": Qt.white, + "Text": Qt.white, + "Button": QColor(53, 53, 53), + "ButtonText": Qt.white, + "BrightText": Qt.red, + "Highlight": QColor(255, 128, 0), + "HighlightedText": Qt.black, + } + } + for style, colors in styles.items(): + palette = QPalette() + for entry, color in colors.items(): + palette.setColor(getattr(QPalette, entry), color) + if color == Qt.darkGray: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), QColor(53, 53, 53) + ) + else: + palette.setColor( + QPalette.Disabled, getattr(QPalette, entry), Qt.darkGray + ) + self.styles[style] = palette + self.styles["Light"] = self.style().standardPalette() + + +class ED_LRR(Ui_ED_LRR): + dl_thread = None + diag_prog = None + dl_started = None + system_found = pyqtSignal("PyQt_PyObject") + + def __init__(self): + super().__init__() + self.config = cfg.load() + self.jobs = {} + + def new_job(self, cls, *args, **kwargs): + print("CREATE JOB:", cls, args, kwargs) + name = cls.__name__ + if name in self.jobs and self.jobs[name].done(): + del self.jobs[name] + if not name in self.jobs: + self.jobs[name] = Job(self.app, self.main_window, cls, *args, **kwargs) + return self.jobs[name] + + def get_open_file(self, filetypes, callback=None): + fileName, _ = QFileDialog.getOpenFileName( + self.main_window, + "Open file", + str(cfg.data_dir), + filetypes, + options=QFileDialog.DontUseNativeDialog, + ) + if callback: + return callback(fileName) + return fileName + + def get_save_file(self, filetypes, callback=None): + fileName, _ = QFileDialog.getSaveFileName( + self.main_window, + "Save file", + str(cfg.data_dir), + filetypes, + options=QFileDialog.DontUseNativeDialog, + ) + if callback: + return callback(fileName) + return fileName + + def set_sys_lst(self, path): + if path not in self.config.history_out_path: + self.config.history_out_path.append(path) + self.inp_sys_lst.addItem(path) + self.inp_out_pp.addItem(path) + self.inp_sys_lst.setCurrentText(path) + self.inp_out_pp.setCurrentText(path) + + def set_bodies_file(self, path): + if path not in self.config.history_bodies_path: + self.config.history_bodies_path.append(path) + self.inp_bodies_pp.addItem(path) + + def set_systems_file(self, path): + if path not in self.config.history_systems_path: + self.config.history_systems_path.append(path) + self.inp_systems_pp.addItem(path) + + def update_dropdowns(self): + return + + def log(self, *args): + t = datetime.today() + msg_t = "[{}] {}".format(t, str.format(*args)) + self.txt_log.append(msg_t) + + def set_comp_mode(self, _): + if self.rd_comp.isChecked(): + comp_mode = "Compute Route" + self.btn_add.setText("Add") + if self.rd_precomp.isChecked(): + comp_mode = "Precompute Graph" + self.btn_add.setText("Select") + self.log("COMP_MODE", comp_mode) + self.lst_sys.setEnabled(self.rd_comp.isChecked()) + self.btn_rm.setEnabled(self.rd_comp.isChecked()) + self.cmb_mode.setEnabled(self.rd_comp.isChecked()) + self.chk_permute.setEnabled(self.rd_comp.isChecked()) + self.lbl_keep.setEnabled(self.rd_comp.isChecked()) + self.lbl_mode.setEnabled(self.rd_comp.isChecked()) + self.chk_permute_keep_first.setEnabled(self.rd_comp.isChecked()) + self.chk_permute_keep_last.setEnabled(self.rd_comp.isChecked()) + self.set_route_mode(self.rd_precomp.isChecked() or None) + + def set_route_mode(self, mode=None): + if mode == None: + mode = self.cmb_mode.currentText() + self.lbl_greedyness.setEnabled(mode == "A*-Search") + self.sld_greedyness.setEnabled(mode == "A*-Search") + + def set_greedyness(self, value): + self.lbl_greedyness.setText("Greedyness Factor ({:.0%})".format(value / 100)) + + @property + def systems(self): + ret = [] + for n in range(self.lst_sys.topLevelItemCount()): + ret.append(self.sys_to_dict(n)) + return ret + + def sys_to_dict(self, n): + header = [ + self.lst_sys.headerItem().data(c, 0) + for c in range(self.lst_sys.headerItem().columnCount()) + ] + system = [ + self.lst_sys.topLevelItem(n).data(c, 0) + for c in range(self.lst_sys.topLevelItem(n).columnCount()) + ] + ret = dict(zip(header, system)) + ret["id"] = getattr(self.lst_sys.topLevelItem(n), "__id__", None) + ret.pop(None, None) + return ret + + def error(self, msg): + QMessageBox.critical(self.main_window, "ERROR!", msg) + + def get_sys_list(self): + if not self.inp_sys_lst.currentText(): + self.error("System list is required!") + return + path = pathlib.Path(self.inp_sys_lst.currentText()) + if not path.exists(): + self.error("System list does not exist, run download and preprocess first!") + return + return path + + def route_progress(self, job, state): + print("RP:", job, state) + + def run(self): + if not all(s["Type"] for s in self.systems): + self.error('Not all systens have been resolved, please click "Search All"') + return + print(self.systems) + systems = [str(s["id"]) for s in self.systems] + jump_range = self.sb_range.value() + mode = self.cmb_mode.currentText() + primary = self.chk_primary.isChecked() + keep_first = self.chk_permute_keep_first.isChecked() + keep_last = self.chk_permute_keep_last.isChecked() + permute = self.chk_permute.isChecked() + greedyness = ( + self.sld_greedyness.value() / 100 + if self.sld_greedyness.isEnabled() + else None + ) + path = self.get_sys_list() + if path is None: + return + precomp = None + path = str(path) + mode = { + "Breadth-First Search": "bfs", + "A*-Search": "astar", + "Greedy-Search": "greedy", + }[mode] + print( + systems, + jump_range, + mode, + primary, + permute, + (keep_first, keep_last), + greedyness, + path, + precomp, + ) + route_job = self.new_job( + Router, + systems, + jump_range, + 0.1, + mode, + primary, + permute, + keep_first, + keep_last, + greedyness, + precomp, + path, + ) + if route_job: + self.route_progress_dialog = ProgressDialog( + "Computing route...", "Cancel", 0, 100, self.main_window + ) + self.route_progress_dialog.canceled.connect(route_job.cancel) + route_job.start() + self.route_progress_dialog.show() + else: + self.error("Another route job is already running!") + + def find_sys_by_names(self, names): + t_s = datetime.today() + if not self.get_sys_list(): + return None + # TODO: start thread/subprocess + ret = _ed_lrr.find_sys(names, self.inp_sys_lst.currentText()) + print("Took:", datetime.today() - t_s) + return ret + + def resolve_systems(self): + # TODO: show spinner + names = [] + for n in range(self.lst_sys.topLevelItemCount()): + names.append(self.sys_to_dict(n)["Name"]) + systems = self.find_sys_by_names(names) + if systems is None: + return + for i, name in enumerate(names): + _, system = systems[name] + self.lst_sys.topLevelItem(i).setData(0, 0, system["system"]) + self.lst_sys.topLevelItem(i).setData(1, 0, system["star_type"]) + self.lst_sys.topLevelItem(i).__id__ = system["id"] + # diff, item = self.find_sys_by_name(name) + # print("Found", (diff, item)) + + def add_system(self): + name = self.inp_sys.text() + item = QTreeWidgetItem(self.lst_sys, [name, None]) + item.resolved = False + item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) + + def remove_system(self): + root = self.lst_sys.invisibleRootItem() + for item in self.lst_sys.selectedItems(): + root.removeChild(item) + + def dl_canceled(self): + if self.dl_thread: + print("Cancel!") + try: + self.dl_thread.progress.disconnect() + except TypeError: + pass + self.dl_thread.stop() + self.dl_thread.wait() + self.diag_prog.close() + self.dl_thread = None + self.diag_prog = None + self.dl_started = None + + def handle_dl_progress(self, args): + filename = os.path.split(args["outfile"])[-1] + if self.diag_prog is None: + self.diag_prog = ProgressDialog("", "Cancel", 0, 1000, self.main_window) + if self.dl_thread: + self.diag_prog.canceled.connect(self.dl_canceled) + self.diag_prog.show() + t_elapsed = datetime.today() - self.dl_started + rate = args["done"] / t_elapsed.total_seconds() + remaining = (args["size"] - args["done"]) / rate + rate = round(rate, 2) + # print(rate, remaining) + try: + t_rem = timedelta(seconds=remaining) + except OverflowError: + t_rem = "-" + msg = "Downloading {} [{}/{}] ({}/s)\n[{}/{}]".format( + filename, + sizeof_fmt(args["done"]), + sizeof_fmt(args["size"]), + sizeof_fmt(rate), + t_round(t_elapsed), + t_round(t_rem), + ) + self.diag_prog.setLabelText(msg) + self.diag_prog.setWindowTitle("Downloading EDSM Dumps") + self.diag_prog.setValue((args["done"] * 1000) // args["size"]) + + def run_download(self): + if self.dl_thread: + return + self.dl_started = datetime.today() + self.dl_thread = DownloadThread( + self.inp_systems_dl.currentText(), + self.inp_systems_dest_dl.currentText(), + self.inp_bodies_dl.currentText(), + self.inp_bodies_dest_dl.currentText(), + ) + self.dl_thread.progress.connect(self.handle_dl_progress) + self.dl_thread.start() + print(".") + + def update_permute_chk(self, state): + self.chk_permute_keep_first.setEnabled(state) + self.chk_permute_keep_last.setEnabled(state) + self.lbl_keep.setEnabled(state) + + def setup_signals(self): + self.btn_download.clicked.connect(self.run_download) + self.inp_systems_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\s.json") + self.inp_bodies_dest_dl.setCurrentText(r"D:\devel\rust\ed_lrr_gui\DL\b.json") + self.set_greedyness(self.sld_greedyness.value()) + self.cmb_mode.currentTextChanged.connect(self.set_route_mode) + self.rd_comp.toggled.connect(self.set_comp_mode) + self.rd_precomp.toggled.connect(self.set_comp_mode) + self.sld_greedyness.valueChanged.connect(self.set_greedyness) + self.btn_go.clicked.connect(self.run) + self.btn_add.clicked.connect(self.add_system) + self.btn_rm.clicked.connect(self.remove_system) + self.chk_permute.stateChanged.connect(self.update_permute_chk) + self.btn_search.clicked.connect(self.resolve_systems) + self.btn_out_browse_pp.clicked.connect( + lambda: self.get_save_file("CSV File (*.csv)", self.set_sys_lst) + ) + self.btn_sys_lst_browse.clicked.connect( + lambda: self.get_open_file("CSV File (*.csv)", self.set_sys_lst) + ) + + self.btn_bodies_browse_pp.clicked.connect( + lambda: self.get_open_file("JSON File (*.json)", self.set_bodies_file) + ) + self.btn_bodies_dest_browse_dl.clicked.connect( + lambda: self.get_save_file("JSON File (*.json)", self.set_bodies_file) + ) + self.btn_systems_browse_pp.clicked.connect( + lambda: self.get_open_file("JSON File (*.json)", self.set_systems_file) + ) + self.btn_systems_dest_browse_dl.clicked.connect( + lambda: self.get_save_file("JSON File (*.json)", self.set_systems_file) + ) + + def handle_close(self): + cfg.write(self.config) + print("BYEEEEEE!") + + def setup_styles(self, win, app): + for name in app.styles: + action = QAction(app) + action.setObjectName("action_load_style_" + name) + action.setText(name) + action.triggered.connect(lambda _, name=name: app.set_style(name)) + self.menuStyle.addAction(action) + + def setupUi(self, MainWindow, app): + super().setupUi(MainWindow) + self.update_dropdowns() + self.main_window = MainWindow + self.app = app + self.setup_signals() + self.lst_sys.setHeaderLabels(["Name", "Type"]) + self.set_route_mode() + self.update_permute_chk(self.chk_permute.isChecked()) + self.setup_styles(MainWindow, app) + + +def main(): + MP.freeze_support() + app = App() + app.setWindowIcon(QIcon(r'D:\devel\rust\ed_lrr_gui\icon\icon.ico')) + MainWindow = QMainWindow() + MainWindow.setWindowIcon(QIcon(r'D:\devel\rust\ed_lrr_gui\icon\icon.ico')) + ui = ED_LRR() + ui.setupUi(MainWindow, app) + MainWindow.show() + ret = app.exec_() + ui.handle_close() + exit(ret) + + +if __name__ == "__main__": + main() diff --git a/ed_lrr_gui/preprocess.py b/ed_lrr_gui/preprocess.py index f59b2b4..a487833 100644 --- a/ed_lrr_gui/preprocess.py +++ b/ed_lrr_gui/preprocess.py @@ -1,8 +1,9 @@ -from multiprocessing import Process, Queue, freeze_support import queue -from datetime import datetime, timedelta -import _ed_lrr from collections import namedtuple +from datetime import datetime, timedelta +from multiprocessing import Process, Queue, freeze_support + +import _ed_lrr class Preprocessor(Process): diff --git a/ed_lrr_gui/router.py b/ed_lrr_gui/router.py index 4e5bbfe..c9f99ce 100644 --- a/ed_lrr_gui/router.py +++ b/ed_lrr_gui/router.py @@ -1,8 +1,16 @@ -from multiprocessing import Process, Queue, freeze_support import queue -from datetime import datetime, timedelta -import _ed_lrr from collections import namedtuple +from datetime import datetime, timedelta +from multiprocessing import Process, Queue, freeze_support + +import _ed_lrr +# from PyQt5.QtWidgets import QProgressDialog + + +# class RouteProgress(QProgressDialog): +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# self.setWindowModality(Qt.WindowModal) class Router(Process): diff --git a/icon/icon.ico b/icon/icon.ico new file mode 100644 index 0000000..e46e62b Binary files /dev/null and b/icon/icon.ico differ diff --git a/icon/make.py b/icon/make.py new file mode 100644 index 0000000..d9db674 --- /dev/null +++ b/icon/make.py @@ -0,0 +1,115 @@ +import svgwrite +import random +import time +from math import factorial +from itertools import permutations +import tsp as m_tsp + +def dist(p1,p2): + return dist2(p1,p2)**0.5 + + +def dist2(p1,p2): + diff=0 + for a,b in zip(p1,p2): + diff+=(a-b)**2 + return diff + + +def tsp(points): + res=[] + for idx in m_tsp.tsp(points)[1]: + res.append(points[idx]) + return res + + +def make_points(n,size,min_dist=0): + min_dist*=min_dist + points=[] + while len(points)0.8: + dwg.add(dwg.circle((px,py),r=base_r+random.random()*base_r,stroke_width=w,stroke='#0ae')).fill('#0ae') + else: + dwg.add(dwg.circle((px,py),r=base_r+random.random()*base_r,stroke_width=w,stroke=color)).fill(color) + r=base_r + for _ in range(random.randint(1,max_rings)): + if small: + random.random() + random.random() + continue + r+=ring_step(random.random()) + if random.random()>0.75: + circ=dwg.add(dwg.circle((px,py),r=r,stroke_width=w,stroke="#ea0")) + else: + circ=dwg.add(dwg.circle((px,py),r=r,stroke_width=w,stroke=color)) + circ.fill(color,opacity=0) + + dwg.save() + + + +seed=0 +generate(seed,"icon_1",small=False) +generate(seed,"icon_1_small",small=True) diff --git a/icon/out/icon_1.svg b/icon/out/icon_1.svg new file mode 100644 index 0000000..1fb9797 --- /dev/null +++ b/icon/out/icon_1.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/icon/out/icon_1_small.svg b/icon/out/icon_1_small.svg new file mode 100644 index 0000000..e31b894 --- /dev/null +++ b/icon/out/icon_1_small.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/installer/ED_LRR.iss b/installer/ED_LRR.iss new file mode 100644 index 0000000..8e31873 --- /dev/null +++ b/installer/ED_LRR.iss @@ -0,0 +1,22 @@ +[Setup] +AppName = "ED_LRR" +AppVersion ="0.1.0" +; WizardStyle = modern +DefaultDirName = {autopf}\ED_LRR +DefaultGroupName=ED_LRR +Compression = lzma/ultra +SolidCompression = true +InternalCompressLevel = ultra +OutputBaseFilename="ED_LRR Setup" +ChangesEnvironment = true + +[Files] +Source: "..\exe\dist\ED_LRR\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs + +[Icons] +Name: "{group}\ED_LRR"; Filename: "{app}\ED_LRR.exe"; WorkingDir: "{app}" +Name: "{group}\Uninstall ED_LRR"; Filename: "{uninstallexe}" + +[Run] +Filename: "{app}\ED_LRR.exe"; Description: "Launch ED_LRR"; Flags: postinstall nowait skipifsilent unchecked +Filename: "{app}\ED_LRR.exe"; Parameters: "download" \ No newline at end of file diff --git a/rust/.cargo/config b/rust/.cargo/config index f0b7483..a5af40a 100644 --- a/rust/.cargo/config +++ b/rust/.cargo/config @@ -1,2 +1,2 @@ [build] -rustflags = ["-C", "target-cpu=native"] \ No newline at end of file +rustflags = ["-C", "target-cpu=native"] diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 4ccdea1..5ce2860 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -8,15 +8,6 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "atty" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "autocfg" version = "0.1.5" @@ -29,14 +20,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "block-buffer" version = "0.7.3" @@ -64,7 +50,7 @@ dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -77,47 +63,6 @@ name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cfg-if" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clicolors-control" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "console" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "csv" version = "1.1.1" @@ -127,7 +72,7 @@ dependencies = [ "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -163,12 +108,11 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -179,11 +123,6 @@ name = "either" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "encode_unicode" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fnv" version = "1.0.6" @@ -209,42 +148,51 @@ dependencies = [ [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "indicatif" -version = "0.11.0" +name = "indoc" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "indoc-impl" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inventory" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inventory-impl" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,41 +220,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lock_api" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mashup" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mashup-impl" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -317,41 +239,29 @@ dependencies = [ "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "number_prefix" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "parking_lot" -version = "0.9.0" +name = "paste" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "parking_lot_core" -version = "0.6.2" +name = "paste-impl" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -366,17 +276,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.4.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc-macro2" version = "0.4.30" @@ -386,39 +293,51 @@ dependencies = [ ] [[package]] -name = "pyo3" -version = "0.7.0" +name = "proc-macro2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", - "mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pyo3" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3cls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pyo3-derive-backend" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pyo3cls" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pyo3-derive-backend 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -435,18 +354,21 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.1.56" +name = "quote" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "regex" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -460,12 +382,12 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rstar" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -473,40 +395,14 @@ dependencies = [ "pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ryu" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "scopeguard" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,7 +425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -544,14 +440,9 @@ dependencies = [ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "smallvec" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "spin" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -570,11 +461,13 @@ dependencies = [ ] [[package]] -name = "termios" -version = "0.3.1" +name = "syn" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -590,116 +483,85 @@ name = "typenum" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-width" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unindent" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum bstr 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e0a692f1c740e7e821ca71a22cf99b9b2322dfa94d10f71443befb1797b3946a" "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum clicolors-control 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73abfd4c73d003a674ce5d2933fca6ce6c42480ea84a5ffe0a2dc39ed56300f9" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" "checksum ctor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3b4c17619643c1252b5f690084b82639dd7fac141c57c8e77a00e0148132092c" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" -"checksum encode_unicode 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90b2c9496c001e8cb61827acdefad780795c42264c137744cae6f7d9e3450abd" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum ghost 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5297b71943dc9fea26a3241b178c140ee215798b7f79f7773fd61683e25bca74" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" -"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" -"checksum inventory 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21df85981fe094480bc2267723d3dc0fd1ae0d1f136affc659b7398be615d922" -"checksum inventory-impl 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8a877ae8bce77402d5e9ed870730939e097aad827b2a932b361958fa9d6e75aa" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +"checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8" +"checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" +"checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" +"checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" -"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" -"checksum mashup 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f2d82b34c7fb11bb41719465c060589e291d505ca4735ea30016a91f6fc79c3b" -"checksum mashup-impl 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "aa607bfb674b4efb310512527d64266b065de3f894fc52f84efcbf7eaa5965fb" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +"checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" +"checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" -"checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" -"checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" +"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum pyo3 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09e6e2d3fa5ae1a8af694f865e03e763e730768b16e3097851ff0b7f2276086" -"checksum pyo3-derive-backend 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9d7ae8ab3017515cd7c82d88ce49b55e12a56c602dc69993e123da45c91b186" -"checksum pyo3cls 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c494f8161f5b73096cc50f00fbb90fe670f476cde5e59c1decff39b546d54f40" +"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum pyo3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5862a106c576591645b9fa36b56764b6c894dda70800479892997e5b4fd41c0f" +"checksum pyo3-derive-backend 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "20d6d14afa2d06a63331dad47b4b40cac06c3be1e3d7de56d020eab2b3e9484b" +"checksum pyo3cls 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e39529c2416febd394f7d032abbce5fa1915e32b2fc9b564e1d9d017acac78d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" -"checksum rstar 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90bb34cd8efef7ed3ebfb29e713e51301c3e60fba37c3e9185a1afaf9ce643a" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum rstar 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08c3cf91d6318ed050a8dda79bc857665f9c3d41524b6f70bbd0396c5d9d662d" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" +"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a" "checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "032c03039aae92b350aad2e3779c352e104d919cb192ba2fabbd7b831ce4f0f6" "checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e" -"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d0d32a92c9ed197278e09140c32dec854ad5826f0e0e18c1d2a1690f15c8d5" +"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 2a579f7..df5607e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,32 +1,27 @@ -[package] -name = "ed_lrr" -version = "0.1.0" -authors = ["Daniel Seiller "] -edition = "2018" -repository = "https://gitlab.com/Earthnuker/ed_lrr.git" -license = "WTFPL" - - -[lib] -crate-type = ["cdylib"] - -[profile.release] -#debug=true - -[dependencies] -csv = "1.1.1" -serde = { version = "1.0", features = ["derive"] } -rstar = "0.5.0" -humantime = "1.2.0" -permutohedron = "0.2.4" -serde_json = "1.0.40" -indicatif = "0.11.0" -fnv = "1.0.6" -bincode = "1.1.4" -sha3 = "0.8.2" -byteorder = "1.3.2" -strsim = "0.9.2" - -[dependencies.pyo3] -version = "0.7.0" -features = ["extension-module"] +[package] +name = "ed_lrr" +version = "0.1.0" +authors = ["Daniel Seiller "] +edition = "2018" +repository = "https://gitlab.com/Earthnuker/ed_lrr.git" +license = "WTFPL" + + +[lib] +crate-type = ["cdylib"] +name = "_ed_lrr" + +[dependencies] +pyo3 = { version = "0.8.0", features = ["extension-module"] } +csv = "1.1.1" +serde = { version = "1.0", features = ["derive"] } +rstar = "0.5.1" +humantime = "1.3.0" +permutohedron = "0.2.4" +serde_json = "1.0.40" +fnv = "1.0.6" +bincode = "1.1.4" +sha3 = "0.8.2" +byteorder = "1.3.2" +strsim = "0.9.2" + diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 43bf006..8204e74 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -114,7 +114,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { py: Python<'static>, hops: Vec, range: f32, - radius_mult: f32, + prune: Option<(usize,f64)>, mode: String, primary: bool, permute: bool, @@ -145,13 +145,14 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { state_dict.set_item("prc_done", state.prc_done)?; state_dict.set_item("n_seen", state.n_seen)?; state_dict.set_item("prc_seen", state.prc_seen)?; + state_dict.set_item("from", state.from.clone())?; + state_dict.set_item("to", state.to.clone())?; callback.call(py, (state_dict,), None) }; let mut systems = Vec::new(); for sys in hops { systems.push(route::SysEntry::parse(&sys)) } - println!("SYSTEMS: {:?}", systems); let opts = RouteOpts { systems, range: Some(range), @@ -165,7 +166,7 @@ pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { keep_first, keep_last, primary, - radius_mult, + prune, }; let none = ().to_object(py); match route(opts) { diff --git a/rust/src/route.rs b/rust/src/route.rs index 3a7878f..247084b 100644 --- a/rust/src/route.rs +++ b/rust/src/route.rs @@ -20,6 +20,8 @@ pub struct SearchState { pub mode: String, pub system: String, pub body: String, + pub from: String, + pub to: String, pub depth: usize, pub queue_size: usize, pub d_rem: f32, @@ -55,7 +57,7 @@ pub struct RouteOpts { pub keep_last: bool, pub factor: Option, pub mode: Mode, - pub radius_mult: f32, + pub prune: Option<(usize,f64)>, pub systems: Vec, pub callback: Box PyResult>, } @@ -191,7 +193,8 @@ pub struct Router { range: f32, primary_only: bool, path: PathBuf, - radius_mult: f32, + prune: Option<(usize,f64)>, + prune_map: FnvHashMap, callback: Box PyResult>, } @@ -199,7 +202,7 @@ impl Router { pub fn new( path: &PathBuf, range: f32, - radius_mult: f32, + prune: Option<(usize,f64)>, primary_only: bool, callback: Box PyResult>, ) -> Result { @@ -245,7 +248,8 @@ impl Router { cache: LineCache::new(path), path: path.clone(), callback, - radius_mult, + prune, + prune_map: FnvHashMap::default() }; println!( "{} Systems loaded in {}", @@ -302,7 +306,8 @@ impl Router { primary_only: primary, path, callback, - radius_mult: 0f32, + prune: None, + prune_map: FnvHashMap::default() }, )) } @@ -317,11 +322,8 @@ impl Router { fn valid(&self, sys: &System, src: &System, dst: &System) -> bool { let scoopable = self.scoopable.contains(&sys.id); - if self.radius_mult == 0.0 { - return scoopable; - } - let df = src.distp(dst); - (sys.distp(src) + sys.distp(dst)) < (df * (1.0 + self.radius_mult)) + return scoopable; + // TODO: check prune map } pub fn best_multiroute( @@ -466,6 +468,8 @@ impl Router { prc_done: 0.0, n_seen: 0, prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), body: start_sys.body.clone(), system: start_sys.system.clone(), }; @@ -569,6 +573,8 @@ impl Router { prc_done: 0.0, n_seen: 0, prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), body: start_sys.body.clone(), system: start_sys.system.clone(), }; @@ -793,6 +799,8 @@ impl Router { prc_done: 0.0, n_seen: 0, prc_seen: 0.0, + from: src_name.clone(), + to: dst_name.clone(), system: start_sys.system.clone(), body: start_sys.body.clone(), }; @@ -879,6 +887,7 @@ impl Router { } } pub fn route(opts: RouteOpts) -> Result>, String> { + // TODO: implement pruning (check if dist to target improved by at least $n*jump_range$ Ly in the last $m$ steps) if opts.systems.is_empty() { if opts.precomp_file.is_some() { return Err("Error: Please specify exatly one system".to_owned()); @@ -898,7 +907,7 @@ pub fn route(opts: RouteOpts) -> Result>, String> { Router::new( &path, opts.range.unwrap(), - opts.radius_mult, + opts.prune, opts.primary, Box::new(opts.callback), )? @@ -906,14 +915,12 @@ pub fn route(opts: RouteOpts) -> Result>, String> { Router::new( &path, opts.range.unwrap(), - opts.radius_mult, + opts.prune, opts.primary, opts.callback, )? }; - let systems: Vec = router - .resolve_systems(&opts.systems)? - .to_vec(); + let systems: Vec = router.resolve_systems(&opts.systems)?.to_vec(); if opts.precompute { for sys in systems { router.route_tree = None; diff --git a/setup.py b/setup.py index 20e467c..af29aac 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,21 @@ -from setuptools import setup,find_packages +import sys +import distutils.cmd +import distutils.log +from setuptools import find_packages, setup from setuptools_rust import Binding, RustExtension, Strip +with open("README.md", "r") as fh: + long_description = fh.read() + + setup( name="ed_lrr_gui", version="0.1.0", author="Daniel Seiller", author_email="earthnuker@gmail.com", + description="Elite: Dangerous long range route plotter", + long_description=long_description, + long_description_content_type="text/markdown", url="none yet", rust_extensions=[ RustExtension( @@ -17,14 +27,38 @@ setup( ) ], packages=find_packages(), - entry_points={"console_scripts": ["ed_lrr_gui=ed_lrr_gui.__main__:main"]}, + entry_points={ + "console_scripts": [ + "ed_lrr_gui_console = ed_lrr_gui.gui.__main__:main", + "ed_lrr = ed_lrr_gui.__main__:main", + ], + "gui_scripts": ["ed_lrr_gui = ed_lrr_gui.gui.__main__:main"], + }, install_requires=[ - "PyQt5", "appdirs", "PyYAML", "requests", "python-dateutil", "pyperclip", + "click", + "PyQt5", + "click-default-group" + ], + setup_requires=[ + "setuptools", + "setuptools-rust", + "wheel", + "pyinstaller", + "pytest-runner", + ], + tests_require=["pytest", "pytest-pep8", "pytest-cov"], + extras_require={ + "dev": ["black", "pyinstaller","jinja2","svgwrite","tsp"], + }, + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", ], include_package_data=True, zip_safe=False, diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..3212d14 --- /dev/null +++ b/tox.ini @@ -0,0 +1,30 @@ +[tox] +envlist = py37 +requires = tox-conda + +[testenv] +recreate = True +skip_install = True +deps = + PyQt5 + setuptools_rust +conda_deps = + pycrypto + nuitka +passenv = + CARGO_HOME + RUSTUP_HOME + INCLUDE + LIB + MSSdk + DISTUTILS_USE_SDK +whitelist_externals = + cargo +conda_channels = + conda-forge +extras = + dev +commands = + python build_gui.py + pip install .[dev] + python -m nuitka --plugin-enable=multiprocessing --plugin-enable=qt-plugins --standalone --follow-imports --output-dir=exe ed_lrr_gui\__main__.py