Compare commits

..

1 Commits

Author SHA1 Message Date
c5ee87535a WIP 2024-03-01 22:44:31 +01:00
9 changed files with 52 additions and 22 deletions

View File

@ -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"

17
Pipfile.lock generated
View File

@ -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": [

View File

@ -24,6 +24,7 @@ install_requires =
packaging
loguru
browser_cookie3
pebble
[options.packages.find]
where = src

View File

@ -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()

View File

@ -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):
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:

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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