checkpoint. beginning download process
This commit is contained in:
30
portable_computing_toolkit_installer/tests/test_json.py
Normal file
30
portable_computing_toolkit_installer/tests/test_json.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import json
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from urllib.request import urlopen
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
json_url = "https://raw.githubusercontent.com/norweeg/portable-computing-toolkit-installer/initial_dev/portable_computing_toolkit_installer/resources/supported_tools.json"
|
||||||
|
|
||||||
|
class TestJSON(object):
|
||||||
|
def test_json_url_valid(self):
|
||||||
|
global json_url
|
||||||
|
parsed = urlparse(json_url)
|
||||||
|
assert len(parsed) == 6
|
||||||
|
assert Path(parsed.path).suffix == ".json"
|
||||||
|
|
||||||
|
def test_json_accessible(self):
|
||||||
|
global json_url
|
||||||
|
json_file = urlopen(json_url)
|
||||||
|
assert json_file.code < 400
|
||||||
|
json_file.close()
|
||||||
|
|
||||||
|
def test_json_valid(self):
|
||||||
|
global json_url
|
||||||
|
with urlopen(json_url) as json_file:
|
||||||
|
json_data = json.load(json_file)
|
||||||
|
assert json_data
|
||||||
|
|
||||||
|
|
||||||
26
portable_computing_toolkit_installer/tests/test_pages.py
Normal file
26
portable_computing_toolkit_installer/tests/test_pages.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import json
|
||||||
|
from urllib.request import urlopen
|
||||||
|
import requests
|
||||||
|
from pathlib import Path
|
||||||
|
from parsel import Selector
|
||||||
|
from w3lib.url import canonicalize_url
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
json_url = "https://raw.githubusercontent.com/norweeg/portable-computing-toolkit-installer/initial_dev/portable_computing_toolkit_installer/resources/supported_tools.json"
|
||||||
|
|
||||||
|
class TestPages(object):
|
||||||
|
def test_pages_accessible(self):
|
||||||
|
global json_url
|
||||||
|
with urlopen(json_url) as json_file:
|
||||||
|
json_data = json.load(json_file)
|
||||||
|
with requests.Session() as session:
|
||||||
|
for page in [canonicalize_url(item["homepage"]) for item in json_data]:
|
||||||
|
try:
|
||||||
|
response = session.get(page, allow_redirects = True, verify = False)
|
||||||
|
except:
|
||||||
|
response = session.get(page.replace("http", "https", 1), allow_redirects = True, verify = False)
|
||||||
|
assert response.status_code < 400
|
||||||
|
html = response.text
|
||||||
|
assert html
|
||||||
|
assert Selector(text = html, type="html").getall()
|
||||||
@@ -1,18 +1,23 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from queue import Queue, Empty
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtNetwork, QtWebEngineWidgets, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtNetwork, QtWebEngineWidgets, QtWidgets
|
||||||
from PyQt5.uic import loadUi
|
from PyQt5.uic import loadUi
|
||||||
|
|
||||||
|
|
||||||
class Downloader(QtWidgets.QMainWindow):
|
class Downloader(QtWidgets.QMainWindow):
|
||||||
def __init__(self, tool_name, tool_info, download_directory, parent = None, flags = None):
|
|
||||||
|
download_progress = QtCore.pyqtSignal(str, int, int)
|
||||||
|
|
||||||
|
def __init__(self, download_queue, install_ready, download_directory, parent = None, flags = None):
|
||||||
super().__init__(parent, flags)
|
super().__init__(parent, flags)
|
||||||
loadUi(Path(__file__).parent / "downloader.ui", baseinstance = self)
|
loadUi(Path(__file__).parent / "downloader.ui", baseinstance = self)
|
||||||
self.hide()
|
self.hide()
|
||||||
#create an off-the-record profile, isolated from other Downloader objects
|
#create an off-the-record profile, isolated from other Downloader objects
|
||||||
new_page = QtWebEngineWidgets.QtWebEnginePage(QtWebEngineWidgets.QWebEngineProfile(self.web_view))
|
new_page = QtWebEngineWidgets.QtWebEnginePage(QtWebEngineWidgets.QWebEngineProfile(self.web_view))
|
||||||
self.web_view.setPage(new_page)
|
self.web_view.setPage(new_page)
|
||||||
|
self._load_result = Queue(maxsize=1)
|
||||||
#set application style and decorate pushbuttons
|
#set application style and decorate pushbuttons
|
||||||
self._style = QtWidgets.QApplication.instance().style()
|
self._style = QtWidgets.QApplication.instance().style()
|
||||||
self.setWindowIcon(QtWidgets.QApplication.instance().windowIcon())
|
self.setWindowIcon(QtWidgets.QApplication.instance().windowIcon())
|
||||||
@@ -29,14 +34,10 @@ class Downloader(QtWidgets.QMainWindow):
|
|||||||
self.actionCancel.triggered.connect(self._cancel_manual_search)
|
self.actionCancel.triggered.connect(self._cancel_manual_search)
|
||||||
self.actionCancel_and_Open_Issue_on_Github.triggered.connect(self._cancel_manual_search_open_issue)
|
self.actionCancel_and_Open_Issue_on_Github.triggered.connect(self._cancel_manual_search_open_issue)
|
||||||
#set attributes
|
#set attributes
|
||||||
self._tool_name = tool_name
|
self._download_queue = download_queue
|
||||||
self._tool_info = tool_info
|
self._install_ready = install_ready
|
||||||
self._download_directory = download_directory
|
self._download_directory = download_directory
|
||||||
#name window from attribute
|
|
||||||
self.setWindowTitle(f"Find {self._tool_name}")
|
|
||||||
#get homepage from attributes and set home button to load it
|
|
||||||
self._home_page = tool_info["homepage"]
|
|
||||||
self.home_button.clicked.connect(lambda: self.web_view.load(QtCore.QUrl(self._home_page)))
|
|
||||||
|
|
||||||
def _reload_becomes_stop(self):
|
def _reload_becomes_stop(self):
|
||||||
"""Turns the reload button into a stop button.
|
"""Turns the reload button into a stop button.
|
||||||
@@ -86,15 +87,42 @@ class Downloader(QtWidgets.QMainWindow):
|
|||||||
self.web_view.load(QtCore.QUrl(self._home_page))
|
self.web_view.load(QtCore.QUrl(self._home_page))
|
||||||
|
|
||||||
def begin_auto_search(self):
|
def begin_auto_search(self):
|
||||||
pass
|
try:
|
||||||
|
tool_info = self._download_queue.get(timeout = 1)
|
||||||
|
except Empty:
|
||||||
|
QtCore.QThread.currentThread().quit()
|
||||||
|
else:
|
||||||
|
self._tool_name = tool_info["name"]
|
||||||
|
self._tool_info = tool_info
|
||||||
|
self._home_page = tool_info["homepage"]
|
||||||
|
#name window from attribute
|
||||||
|
self.setWindowTitle(f"Find {self._tool_name}")
|
||||||
|
#get homepage from attributes and set home button to load it
|
||||||
|
self.home_button.clicked.connect(lambda: self.web_view.load(QtCore.QUrl(self._home_page)))
|
||||||
|
self.web_view.loadFinished.connect()
|
||||||
|
|
||||||
def _download_file(self):
|
self._download_file(self._find_installer_url())
|
||||||
|
|
||||||
|
def _find_installer_url(self):
|
||||||
|
self.web_view.load(QtCore.QUrl(self._tool_info["page"]))
|
||||||
|
load_result = self._load_result.get()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _download_file(self, url):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class DownloadWorker(QtCore.QRunnable):
|
class DownloadWorker(QtCore.QRunnable):
|
||||||
def __init__(self, tool_name, tool_info, download_directory):
|
def __init__(self, download_queue, install_ready, download_error, download_directory, wizard):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._downloader = Downloader(tool_name, tool_info, download_directory)
|
self._download_queue = download_queue
|
||||||
|
self._install_ready = install_ready
|
||||||
|
self._download_directory = download_directory
|
||||||
|
self._wizard = wizard
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._downloader.begin_auto_search()
|
downloader = Downloader(self.download_queue, self._install_ready, self._download_error, self._download_directory)
|
||||||
|
downloader.download_progress.connect(self._wizard.track_progress)
|
||||||
|
downloader.begin_auto_search()
|
||||||
@@ -10,6 +10,7 @@ import json
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from itertools import product
|
from itertools import product
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
from PyQt5 import QtCore, QtGui, QtNetwork, QtWebEngineWidgets, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtNetwork, QtWebEngineWidgets, QtWidgets
|
||||||
@@ -24,6 +25,7 @@ except ImportError:
|
|||||||
|
|
||||||
from validators.location_validator import Location_Validator
|
from validators.location_validator import Location_Validator
|
||||||
from .menu_iterator import MenuIterator
|
from .menu_iterator import MenuIterator
|
||||||
|
from .downloader import DownloadWorker, Downloader
|
||||||
|
|
||||||
class InstallerWizard(QtWidgets.QWizard):
|
class InstallerWizard(QtWidgets.QWizard):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@@ -49,6 +51,7 @@ class InstallerWizard(QtWidgets.QWizard):
|
|||||||
self._network_manager = QtNetwork.QNetworkAccessManager(parent=QtWidgets.QApplication.instance())
|
self._network_manager = QtNetwork.QNetworkAccessManager(parent=QtWidgets.QApplication.instance())
|
||||||
self._thread_pool = QtCore.QThreadPool.globalInstance()
|
self._thread_pool = QtCore.QThreadPool.globalInstance()
|
||||||
self._project_page=Path("https://github.com/norweeg/portable-computing-toolkit-installer/")
|
self._project_page=Path("https://github.com/norweeg/portable-computing-toolkit-installer/")
|
||||||
|
self._progress_update_lock = Lock()
|
||||||
|
|
||||||
@QtCore.pyqtSlot("QUrl")
|
@QtCore.pyqtSlot("QUrl")
|
||||||
def _link_clicked(self, address):
|
def _link_clicked(self, address):
|
||||||
@@ -327,3 +330,47 @@ class InstallerWizard(QtWidgets.QWizard):
|
|||||||
self._display_error(f"{str().join(names_of_dependant_items)} {depend_text} on {item.text(0)}")
|
self._display_error(f"{str().join(names_of_dependant_items)} {depend_text} on {item.text(0)}")
|
||||||
item.setCheckState(0, QtCore.Qt.Checked)
|
item.setCheckState(0, QtCore.Qt.Checked)
|
||||||
|
|
||||||
|
def _begin_downloads(self, download_queue = None, install_ready = None, download_directory = None):
|
||||||
|
if download_queue:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._download_queue = Queue()
|
||||||
|
|
||||||
|
if install_ready:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._install_ready = Queue()
|
||||||
|
|
||||||
|
self._download_error = Queue()
|
||||||
|
|
||||||
|
if download_directory:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self._download_directory = QtCore.QTemporaryDir()
|
||||||
|
except Exception as e:
|
||||||
|
self._display_error(str(e), self._download_directory.errorString()).accepted.connect(lambda: self.back())
|
||||||
|
|
||||||
|
if self._download_queue.empty():
|
||||||
|
tools_by_name = {tool["name"]:tool for tool in self.__tools__}
|
||||||
|
self._download_progress = {}
|
||||||
|
for selected_tool in self._get_selections():
|
||||||
|
self._download_queue.put_nowait(tools_by_name[selected_tool.text(0)])
|
||||||
|
self.progress_bar.setRange(0, self._download_queue.qsize())
|
||||||
|
|
||||||
|
while self._thread_pool.activeThreadCount() < self._thread_pool.maxThreadCount() and not self._download_queue.empty():
|
||||||
|
self._thread_pool.tryStart(DownloadWorker(self._download_queue, self._install_ready, self._download_error, self._download_directory, self))
|
||||||
|
QtCore.QThread.currentThread().msleep(250)
|
||||||
|
|
||||||
|
assert self._download_error.empty()
|
||||||
|
|
||||||
|
|
||||||
|
@QtCore.pyqtSignal(str, int, int)
|
||||||
|
def track_progress(self, tool_name, bytes_received, bytes_total):
|
||||||
|
if tool_name not in [tool["name"] for tool in self.__tools__]:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self._download_progress[tool_name] = bytes_received/bytes_total
|
||||||
|
self._progress_update_lock.acquire()
|
||||||
|
self.progress_bar.setValue(sum(self._download_progress.values()))
|
||||||
|
self._progress_update_lock.release()
|
||||||
|
|||||||
Reference in New Issue
Block a user