[view.qt] refactoring: using a different approach to cancel file downloads to keep compatibility with older Python versions

This commit is contained in:
Vinicius Moreira
2023-12-12 18:14:12 -03:00
parent d0a7da8ffd
commit 3b7b22c9c7
3 changed files with 27 additions and 10 deletions

View File

@@ -1,6 +1,7 @@
import operator import operator
import os import os
from functools import reduce from functools import reduce
from logging import Logger
from threading import Lock from threading import Lock
from typing import List, Optional, Dict from typing import List, Optional, Dict
@@ -71,12 +72,13 @@ class PackagesTable(QTableWidget):
COL_NUMBER = 9 COL_NUMBER = 9
DEFAULT_ICON_SIZE = QSize(16, 16) DEFAULT_ICON_SIZE = QSize(16, 16)
def __init__(self, parent: QWidget, icon_cache: MemoryCache, download_icons: bool): def __init__(self, parent: QWidget, icon_cache: MemoryCache, download_icons: bool, logger: Logger):
super(PackagesTable, self).__init__() super(PackagesTable, self).__init__()
self.setObjectName('table_packages') self.setObjectName('table_packages')
self.setParent(parent) self.setParent(parent)
self.window = parent self.window = parent
self.download_icons = download_icons self.download_icons = download_icons
self.logger = logger
self.setColumnCount(self.COL_NUMBER) self.setColumnCount(self.COL_NUMBER)
self.setFocusPolicy(Qt.NoFocus) self.setFocusPolicy(Qt.NoFocus)
self.setShowGrid(False) self.setShowGrid(False)
@@ -614,9 +616,10 @@ class PackagesTable(QTableWidget):
return reduce(operator.add, [self.columnWidth(i) for i in range(self.columnCount())]) return reduce(operator.add, [self.columnWidth(i) for i in range(self.columnCount())])
def _setup_file_downloader(self, max_workers: int = 50, max_downloads: int = -1) -> None: def _setup_file_downloader(self, max_workers: int = 50, max_downloads: int = -1) -> None:
self.file_downloader = URLFileDownloader(parent=self, self.file_downloader = URLFileDownloader(logger=self.logger,
max_workers=max_workers, max_workers=max_workers,
max_downloads=max_downloads) max_downloads=max_downloads,
parent=self)
self.file_downloader.signal_downloaded.connect(self._update_pkg_icon) self.file_downloader.signal_downloaded.connect(self._update_pkg_icon)
self.file_downloader.start() self.file_downloader.start()

View File

@@ -1117,9 +1117,10 @@ class URLFileDownloader(QThread):
signal_downloaded = pyqtSignal(str, bytes, object) signal_downloaded = pyqtSignal(str, bytes, object)
def __init__(self, max_workers: int = 50, request_timeout: int = 30, inactivity_timeout: int = 3, def __init__(self, logger: Logger, max_workers: int = 50, request_timeout: int = 30, inactivity_timeout: int = 3,
max_downloads: int = -1, parent: Optional[QWidget] = None): max_downloads: int = -1, parent: Optional[QWidget] = None):
super().__init__(parent) super().__init__(parent)
self._logger = logger
self._queue = Queue() self._queue = Queue()
self._max_workers = max_workers self._max_workers = max_workers
self._request_timeout = request_timeout self._request_timeout = request_timeout
@@ -1129,6 +1130,7 @@ class URLFileDownloader(QThread):
def _get(self, url_: str, id_: Optional[object]): def _get(self, url_: str, id_: Optional[object]):
if self._stop: if self._stop:
self._logger.info(f"File '{url_}' download cancelled")
return return
try: try:
@@ -1136,21 +1138,31 @@ class URLFileDownloader(QThread):
content = res.content if res.status_code == 200 else None content = res.content if res.status_code == 200 else None
self.signal_downloaded.emit(url_, content, id_) self.signal_downloaded.emit(url_, content, id_)
except Exception as e: except Exception as e:
sys.stderr.write(f"[ERROR] could not download file from '{url_}': " self._logger.error(f"[ERROR] could not download file from '{url_}': "
f"{e.__class__.__name__}({str(e.args)})\n") f"{e.__class__.__name__}({str(e.args)})\n")
def run(self) -> None: def run(self) -> None:
download_count = 0 download_count = 0
futures = []
with ThreadPoolExecutor(max_workers=self._max_workers) as executor: with ThreadPoolExecutor(max_workers=self._max_workers) as executor:
while not self._stop and (self._max_downloads <= 0 or download_count < self._max_downloads): while not self._stop and (self._max_downloads <= 0 or download_count < self._max_downloads):
try: try:
url_, id_ = self._queue.get(timeout=self._inactivity_timeout) url_, id_ = self._queue.get(timeout=self._inactivity_timeout)
executor.submit(self._get, url_, id_) futures.append(executor.submit(self._get, url_, id_))
download_count += 1 download_count += 1
except Exception: except Exception:
self._stop = True self._stop = True
executor.shutdown(wait=False, cancel_futures=True) cancelled_count = 0
for f in futures:
if not f.done():
f.cancel()
cancelled_count += 1
if cancelled_count > 0:
self._logger.info(f"{cancelled_count} file downloads cancelled")
self._logger.info(f"Finished to download files (count={download_count})")
def stop(self) -> None: def stop(self) -> None:
self._stop = True self._stop = True

View File

@@ -290,8 +290,10 @@ class ManageWindow(QWidget):
self.table_container.setLayout(QVBoxLayout()) self.table_container.setLayout(QVBoxLayout())
self.table_container.layout().setContentsMargins(0, 0, 0, 0) self.table_container.layout().setContentsMargins(0, 0, 0, 0)
self.table_apps = PackagesTable(self, self.icon_cache, self.table_apps = PackagesTable(parent=self,
download_icons=bool(self.config['download']['icons'])) icon_cache=self.icon_cache,
download_icons=bool(self.config['download']['icons']),
logger=logger)
self.table_apps.change_headers_policy() self.table_apps.change_headers_policy()
self.table_container.layout().addWidget(self.table_apps) self.table_container.layout().addWidget(self.table_apps)