From c5ee87535ae9238bf2e7395b630d8534f2ac1e9b Mon Sep 17 00:00:00 2001 From: Faerbit Date: Fri, 1 Mar 2024 22:44:31 +0100 Subject: [PATCH] WIP --- Pipfile | 3 ++- Pipfile.lock | 17 +++++++++++++---- setup.cfg | 1 + src/fime/import_task.py | 6 ++++-- src/fime/main.py | 24 ++++++++++++++++-------- src/fime/task_completer.py | 5 +++-- src/fime/util.py | 6 ++++++ src/fime/worklog.py | 6 ++++-- src/fime/worklog_rest.py | 6 +++--- 9 files changed, 52 insertions(+), 22 deletions(-) diff --git a/Pipfile b/Pipfile index 567a4b7..384a363 100644 --- a/Pipfile +++ b/Pipfile @@ -9,7 +9,8 @@ requests = "~=2.28" requests-futures = "~=1.0" packaging = "~=23.0" loguru = "~=0.6" -browser-cookie3 = "*" +browser-cookie3 = "~=0.19" +pebble = "~=5.0" [dev-packages] pyinstaller = "~=5.6" diff --git a/Pipfile.lock b/Pipfile.lock index e328987..66f50fd 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "236b0d1f3ca2625232ac2e64bf963e188ff5fa85fc570e46f8e877bf13cb98d3" + "sha256": "b9f0e0869765dff4160bfe632eb361b03a8b93bd8d9b19e36d371f2ff76c73f1" }, "pipfile-spec": 6, "requires": { @@ -204,6 +204,15 @@ "markers": "python_version >= '3.7'", "version": "==23.2" }, + "pebble": { + "hashes": [ + "sha256:c8a0659b215ff6dcc974516018fcd95c5c626d8bb9a6668dcfbf85880e6390dc", + "sha256:e7f7ecfd0107ab7cec9f3bb411a856c4d7d552202d4e9a8b038e9a64ae31fd8c" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==5.0.6" + }, "pycryptodomex": { "hashes": [ "sha256:0daad007b685db36d977f9de73f61f8da2a7104e20aca3effd30752fd56f73e1", @@ -355,11 +364,11 @@ }, "pyinstaller-hooks-contrib": { "hashes": [ - "sha256:131494f9cfce190aaa66ed82e82c78b2723d1720ce64d012fbaf938f4ab01d35", - "sha256:51a51ea9e1ae6bd5ffa7ec45eba7579624bf4f2472ff56dba0edc186f6ed46a6" + "sha256:43f3e084ae5f826415399d72ecf2e32328fe859ad7455c7cddfc09f1a61c90b7", + "sha256:8f5ac1acdafde9e553c82242aeae2d2f8fb65ec8e2b0ba416547948108a73e01" ], "markers": "python_version >= '3.7'", - "version": "==2024.1" + "version": "==2024.2" }, "pyproject-hooks": { "hashes": [ diff --git a/setup.cfg b/setup.cfg index a70724e..70ee3ed 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,6 +24,7 @@ install_requires = packaging loguru browser_cookie3 + pebble [options.packages.find] where = src diff --git a/src/fime/import_task.py b/src/fime/import_task.py index 875cd74..02bf9fc 100644 --- a/src/fime/import_task.py +++ b/src/fime/import_task.py @@ -1,3 +1,5 @@ +from concurrent.futures import Executor + try: from PySide6 import QtCore, QtGui, QtWidgets except ImportError: @@ -10,14 +12,14 @@ from fime.util import get_icon class ImportTask(QtWidgets.QDialog): - def __init__(self, config: Config, parent, *args, **kwargs): + def __init__(self, config: Config, executor: Executor, parent, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.setWindowTitle("New Tasks") self.config = config self.line_edit = QtWidgets.QLineEdit(self) - self.completer = TaskCompleter(config) + self.completer = TaskCompleter(config, executor) self.line_edit.setCompleter(self.completer) self.line_edit.textChanged.connect(self.completer.update_picker) self.line_edit.setFocus() diff --git a/src/fime/main.py b/src/fime/main.py index 8318f5e..1a83c62 100755 --- a/src/fime/main.py +++ b/src/fime/main.py @@ -23,7 +23,7 @@ from fime.import_task import ImportTask from fime.report import ReportDialog from fime.settings import Settings from fime.task_edit import TaskEdit -from fime.util import get_screen_height, get_icon +from fime.util import get_screen_height, get_icon, CompatPool class App: @@ -41,7 +41,9 @@ class App: self.menu = QtWidgets.QMenu(None) - self.import_task = ImportTask(self.config, None) + self.executor = CompatPool() + + self.import_task = ImportTask(self.config, self.executor, None) self.import_task.accepted.connect(self.new_task_imported) self.taskEdit = TaskEdit(self.tasks, None) @@ -50,7 +52,7 @@ class App: self.reportDialog = ReportDialog(self.tasks, Report(lcd), None) self.reportDialog.accepted.connect(self.log_edited) - self.worklogDialog = WorklogDialog(self.config, Worklog(lcd), None) + self.worklogDialog = WorklogDialog(self.config, self.executor, Worklog(lcd), None) self.worklogDialog.accepted.connect(self.log_edited) self.settings = Settings(self.config, None) @@ -153,7 +155,7 @@ class App: menu_items.append(("Settings", partial(self.open_new_dialog, self.settings))) menu_items.append(("About", partial(self.open_new_dialog, self.about))) - menu_items.append(("Close", self.app.quit)) + menu_items.append(("Close", self.quit_handler)) if self.config.flip_menu: menu_items.reverse() @@ -169,17 +171,23 @@ class App: action.setIcon(get_icon("go-next")) action.triggered.connect(item[1]) - def sigterm_handler(self, signo, _frame): - logger.debug(f'handling signal "{signal.strsignal(signo)}"') + def quit_handler(self, signo=None, _frame=None): + if signo: + logger.debug(f'handling signal "{signal.strsignal(signo)}"') + logger.debug("Quitting app") self.app.quit() + logger.debug("Shutting down HTTP requests executor") + self.executor.stop() + self.executor.join() + logger.debug("HTTP requests executor is shutdown") def run(self): timer = QtCore.QTimer(None) # interrupt event loop regularly for signal handling timer.timeout.connect(lambda: None) timer.start(500) - signal.signal(signal.SIGTERM, self.sigterm_handler) - signal.signal(signal.SIGINT, self.sigterm_handler) + signal.signal(signal.SIGTERM, self.quit_handler) + signal.signal(signal.SIGINT, self.quit_handler) if PYSIDE_6: self.app.exec() else: diff --git a/src/fime/task_completer.py b/src/fime/task_completer.py index a7b6127..f36436f 100644 --- a/src/fime/task_completer.py +++ b/src/fime/task_completer.py @@ -1,6 +1,7 @@ import os import re import threading +from concurrent.futures import Executor from enum import Enum, auto from functools import reduce, partial from queue import Queue, Empty @@ -27,11 +28,11 @@ class TaskCompleter(QtWidgets.QCompleter): running = QtCore.Signal() stopped = QtCore.Signal() - def __init__(self, config: Config, parent=None, *args, **kwargs): + def __init__(self, config: Config, executor: Executor, parent=None, *args, **kwargs): super().__init__([], parent, *args, **kwargs) self.setFilterMode(QtCore.Qt.MatchFlag.MatchContains) self.setCaseSensitivity(QtCore.Qt.CaseInsensitive) - self.session = FuturesSession() + self.session = FuturesSession(executor=executor) self.session.headers["Accept"] = "application/json" self.config = config self.picker_url = None diff --git a/src/fime/util.py b/src/fime/util.py index 44f1980..156222d 100644 --- a/src/fime/util.py +++ b/src/fime/util.py @@ -2,6 +2,7 @@ import enum import browser_cookie3 from loguru import logger +from pebble import ProcessPool from requests import Session from fime.config import Config, AuthMethods, Browsers @@ -15,6 +16,11 @@ except ImportError: import fime.icons +class CompatPool(ProcessPool): + def submit(self, fn, *args, **kwargs): + return self.schedule(fn, args=args, kwargs=kwargs) + + def get_screen_height(qobject): if hasattr(qobject, "screen"): return qobject.screen().size().height() diff --git a/src/fime/worklog.py b/src/fime/worklog.py index 8ee4405..1b6257d 100644 --- a/src/fime/worklog.py +++ b/src/fime/worklog.py @@ -1,3 +1,4 @@ +from concurrent.futures import Executor from datetime import date from functools import reduce, partial from typing import List, Tuple @@ -95,10 +96,11 @@ class WorklogDialog(QtWidgets.QDialog): if not self.return_ or self.editor.text() == self.initial_text: self.edit_finished_row.emit(row) - def __init__(self, config: Config, worklog: Worklog, parent, *args, **kwargs): + def __init__(self, config: Config, executor: Executor, worklog: Worklog, parent, *args, **kwargs): super().__init__(parent, *args, **kwargs) self.config = config + self.executor = executor self.rest = None self._changing_items = False @@ -176,7 +178,7 @@ class WorklogDialog(QtWidgets.QDialog): def showEvent(self, _): # reinitialize to purge caches and pick up config changes - self.rest = WorklogRest(self.config) + self.rest = WorklogRest(self.config, self.executor) self._worklog.date = date.today() self.update_all() self.upload_button.setEnabled(False) diff --git a/src/fime/worklog_rest.py b/src/fime/worklog_rest.py index 820a1d3..d1041fa 100644 --- a/src/fime/worklog_rest.py +++ b/src/fime/worklog_rest.py @@ -1,5 +1,5 @@ import os -from concurrent.futures import Future +from concurrent.futures import Future, Executor from datetime import date, datetime, timedelta, time from functools import partial from textwrap import dedent @@ -16,13 +16,13 @@ from fime.util import Status, add_auth class WorklogRest: - def __init__(self, config: Config): + def __init__(self, config: Config, executor: Executor): self.config = config self.user_url = os.path.join(config.jira_url, "rest/api/2/myself") self.issue_url = os.path.join(config.jira_url, "rest/api/2/issue/{}") self.worklog_url = os.path.join(config.jira_url, "rest/api/2/issue/{}/worklog") self.worklog_update_url = os.path.join(config.jira_url, "rest/api/2/issue/{issue_key}/worklog/{worklog_id}") - self.session = FuturesSession() + self.session = FuturesSession(executor=executor) self.session.headers["Accept"] = "application/json" add_auth(config, self.session) self._user = None