From 52c41b24ad71b5323af79de837f0198737813d45 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 9 Jun 2019 12:39:26 +0200 Subject: [PATCH] Avoid using 'terminate' on the download thread --- download_window.py | 17 +++++++++----- threads.py | 58 +++++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/download_window.py b/download_window.py index 252675e..f089ede 100644 --- a/download_window.py +++ b/download_window.py @@ -5,6 +5,7 @@ from threads import DownloadThread, ThreadStatus from utilities import pop_up, resource_path from constants import Constants, Messages + Ui_Download_window, _ = uic.loadUiType( resource_path("download_db_window.ui") ) @@ -14,6 +15,7 @@ class DownloadWindow(QWidget, Ui_Download_window): """Subclass QWidget and Ui_Download_window. It is the window displayed during the database download.""" complete = pyqtSignal() + closed = pyqtSignal() def __init__(self): """Initialize the window.""" @@ -38,6 +40,7 @@ class DownloadWindow(QWidget, Ui_Download_window): self._download_thread = DownloadThread() self._download_thread.finished.connect(self._wait_close) self._download_thread.progress.connect(self._display_progress) + self.closed.connect(self._download_thread.set_exit) self.cancel_btn.clicked.connect(self._terminate_process) def start_download(self): @@ -61,12 +64,16 @@ class DownloadWindow(QWidget, Ui_Download_window): elif progress == Constants.EXTRACTING_CODE: self.status_lbl.setText(Constants.EXTRACTING_MSG + '\n') + def _stop_thread(self): + """Ask the download thread to stop.""" + if self._download_thread.isRunning(): + self.closed.emit() + self._download_thread.wait() + @pyqtSlot() def _terminate_process(self): """Terminate the download thread and close.""" - if self._download_thread.isRunning(): - self._download_thread.terminate() - self._download_thread.wait() + self._stop_thread() self.close() @pyqtSlot() @@ -84,7 +91,5 @@ class DownloadWindow(QWidget, Ui_Download_window): def reject(self): """Extends QWidget.reject. Terminate the download thread.""" - if self._download_thread.isRunning(): - self._download_thread.terminate() - self._download_thread.wait() + self._stop_thread() super().reject() diff --git a/threads.py b/threads.py index 04904d2..2c6764a 100644 --- a/threads.py +++ b/threads.py @@ -41,16 +41,17 @@ class DownloadThread(BaseDownloadThread): """Subclass BaseDownloadThread. Download the database, images and audio samples.""" progress = pyqtSignal(int, float) - CHUNK = 1024**2 + _CHUNK = 1024**2 def __init__(self): """Just call super().__init__.""" - self.db = None + self._db = None + self._exit_call = False super().__init__() def _pretty_len(self, byte_obj): """Return a well-formatted number of downloaded MB.""" - mega = len(byte_obj) / self.CHUNK + mega = len(byte_obj) / self._CHUNK if mega.is_integer(): return int(mega) else: @@ -59,40 +60,51 @@ class DownloadThread(BaseDownloadThread): def _get_download_speed(self, data, delta): """Return the download speed in MB/s.""" return round( - (len(data) / self.CHUNK) / delta, 2 + (len(data) / self._CHUNK) / delta, 2 ) + def set_exit(self): + self._exit_call = True + def run(self): """Override QThread.run. Download the database, images and audio samples. Handle all possible exceptions. Also extract the files in the local folder.""" self.status = ThreadStatus.UNDEFINED - self.db = None + self._db = None raw_data = bytes(0) try: - self.db = urllib3.PoolManager().request( + self._db = urllib3.PoolManager().request( 'GET', Database.LINK_LOC, - preload_content=False + preload_content=False, + timeout=4.0 ) while True: start = time() - data = self.db.read(self.CHUNK) - delta = time() - start - if not data: - break - raw_data += data - self.progress.emit( - self._pretty_len(raw_data), - self._get_download_speed(data, delta) - ) - self.db.release_conn() + try: + data = self._db.read(self._CHUNK) + except Exception: + raise + else: + delta = time() - start + if not data: + break + raw_data += data + self.progress.emit( + self._pretty_len(raw_data), + self._get_download_speed(data, delta) + ) + if self._exit_call: + self._exit_call = False + self._db.release_conn() + return except Exception: # No internet connection. - self.db.release_conn() + self._db.release_conn() self.status = ThreadStatus.NO_CONNECTION_ERR return - if self.db.status != 200: + if self._db.status != 200: self.status = ThreadStatus.BAD_DOWNLOAD_ERR return try: @@ -115,14 +127,6 @@ class DownloadThread(BaseDownloadThread): else: self.status = ThreadStatus.OK - def terminate(self): - """Extend QThread.terminate. - - Release the connection in case of termination.""" - if self.db is not None: - self.db.release_conn() - super().terminate() - class _AsyncDownloader: """Mixin class for asynchronous threads."""