Make mypy happier

This commit is contained in:
Odd Stråbø 2024-02-08 15:49:49 +00:00
commit 49f6546aca
19 changed files with 76 additions and 52 deletions

View file

@ -154,7 +154,7 @@ class Connect(object):
def select_servers(self, state=None): def select_servers(self, state=None):
state = state or self.connect_manager.connect({'enableAutoLogin': False}) state = state or self.connect_manager.connect({'enableAutoLogin': False})
user = {} user = {} # TODO: Fixme: content of this dict is used below, but can never contain anything
dialog = ServerConnect("script-jellyfin-connect-server.xml", *XML_PATH) dialog = ServerConnect("script-jellyfin-connect-server.xml", *XML_PATH)
dialog.set_args( dialog.set_args(

View file

@ -8,6 +8,7 @@ import os
import sqlite3 import sqlite3
import sys import sys
import re import re
from typing import Any, Dict
from kodi_six import xbmc, xbmcvfs from kodi_six import xbmc, xbmcvfs
from six import text_type from six import text_type
@ -36,7 +37,7 @@ class Database(object):
''' '''
timeout = 120 timeout = 120
discovered = False discovered = False
discovered_file = None discovered_file: str = None
def __init__(self, db_file=None, commit_close=True): def __init__(self, db_file=None, commit_close=True):
@ -318,7 +319,7 @@ def reset_artwork():
LOG.info("[ reset artwork ]") LOG.info("[ reset artwork ]")
def get_sync(): def get_sync() -> dict:
if (3, 0) <= sys.version_info < (3, 6): if (3, 0) <= sys.version_info < (3, 6):
LOG.error("Python versions 3.0-3.5 are NOT supported.") LOG.error("Python versions 3.0-3.5 are NOT supported.")
@ -342,7 +343,7 @@ def get_sync():
return sync return sync
def save_sync(sync): def save_sync(sync: Dict[str, Any]):
if not xbmcvfs.exists(ADDON_DATA): if not xbmcvfs.exists(ADDON_DATA):
xbmcvfs.mkdirs(ADDON_DATA) xbmcvfs.mkdirs(ADDON_DATA)

View file

@ -4,7 +4,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
################################################################################################## ##################################################################################################
import os import os
from typing import List from typing import List, cast
from kodi_six import xbmcgui, xbmcaddon from kodi_six import xbmcgui, xbmcaddon
from six import ensure_text from six import ensure_text
@ -52,7 +52,7 @@ class ContextMenu(xbmcgui.WindowXMLDialog):
self.getControl(USER_IMAGE).setImage(window('JellyfinUserImage')) self.getControl(USER_IMAGE).setImage(window('JellyfinUserImage'))
LOG.info("options: %s", self._options) LOG.info("options: %s", self._options)
self.list_ = self.getControl(LIST) self.list_ = cast(xbmcgui.ControlList, self.getControl(LIST))
for option in self._options: for option in self._options:
self.list_.addItem(self._add_listitem(option)) self.list_.addItem(self._add_listitem(option))

View file

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals from __future__ import division, absolute_import, print_function, unicode_literals
from typing import Optional
################################################################################################## ##################################################################################################
from kodi_six import xbmc, xbmcgui from kodi_six import xbmc, xbmcgui
@ -22,7 +24,7 @@ START_BEGINNING = 3011
class ResumeDialog(xbmcgui.WindowXMLDialog): class ResumeDialog(xbmcgui.WindowXMLDialog):
_resume_point = None _resume_point = None
selected_option = None selected_option: Optional[int] = None
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs) xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)

View file

@ -885,7 +885,7 @@ def backup():
if xbmcvfs.exists(backup + '/'): if xbmcvfs.exists(backup + '/'):
if not dialog("yesno", "{jellyfin}", translate(33090)): if not dialog("yesno", "{jellyfin}", translate(33090)):
return backup() return backup
delete_folder(backup) delete_folder(backup)

View file

@ -6,6 +6,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
import json import json
import sys import sys
from datetime import datetime from datetime import datetime
from typing import Any, Dict
# Workaround for threads using datetime: _striptime is locked # Workaround for threads using datetime: _striptime is locked
import _strptime # noqa:F401 import _strptime # noqa:F401
@ -37,7 +38,7 @@ class Service(xbmc.Monitor):
monitor = None monitor = None
play_event = None play_event = None
warn = True warn = True
settings = {'last_progress': datetime.today(), 'last_progress_report': datetime.today()} settings: Dict[str, Any] = {'last_progress': datetime.today(), 'last_progress_report': datetime.today()}
def __init__(self): def __init__(self):
@ -264,17 +265,17 @@ class Service(xbmc.Monitor):
window('jellyfin_should_stop.bool', True) window('jellyfin_should_stop.bool', True)
self.running = False self.running = False
elif method in ('SyncLibrarySelection', 'RepairLibrarySelection', 'AddLibrarySelection', 'RemoveLibrarySelection'): elif self.library_thread is not None and method in ('SyncLibrarySelection', 'RepairLibrarySelection', 'AddLibrarySelection', 'RemoveLibrarySelection'):
self.library_thread.select_libraries(method) self.library_thread.select_libraries(method)
elif method == 'SyncLibrary': elif self.library_thread is not None and method == 'SyncLibrary':
if not data.get('Id'): if not data.get('Id'):
return return
self.library_thread.add_library(data['Id'], data.get('Update', False)) self.library_thread.add_library(data['Id'], data.get('Update', False))
xbmc.executebuiltin("Container.Refresh") xbmc.executebuiltin("Container.Refresh")
elif method == 'RepairLibrary': elif self.library_thread is not None and method == 'RepairLibrary':
if not data.get('Id'): if not data.get('Id'):
return return
@ -288,7 +289,7 @@ class Service(xbmc.Monitor):
self.library_thread.add_library(data['Id']) self.library_thread.add_library(data['Id'])
xbmc.executebuiltin("Container.Refresh") xbmc.executebuiltin("Container.Refresh")
elif method == 'RemoveLibrary': elif self.library_thread is not None and method == 'RemoveLibrary':
libraries = data['Id'].split(',') libraries = data['Id'].split(',')
for lib in libraries: for lib in libraries:
@ -309,10 +310,11 @@ class Service(xbmc.Monitor):
self.library_thread = None self.library_thread = None
Jellyfin.close_all() Jellyfin.close_all()
self.monitor.server = [] if self.monitor is not None:
self.monitor.sleep = True self.monitor.server = []
self.monitor.sleep = True
elif method == 'System.OnWake': elif self.monitor is not None and method == 'System.OnWake':
if not self.monitor.sleep: if not self.monitor.sleep:
LOG.warning("System.OnSleep was never called, skip System.OnWake") LOG.warning("System.OnSleep was never called, skip System.OnWake")
@ -365,7 +367,7 @@ class Service(xbmc.Monitor):
self.settings['enable_context_transcode'] = settings('enableContextTranscode.bool') self.settings['enable_context_transcode'] = settings('enableContextTranscode.bool')
LOG.info("New context transcode setting: %s", self.settings['enable_context_transcode']) LOG.info("New context transcode setting: %s", self.settings['enable_context_transcode'])
if settings('useDirectPaths') != self.settings['mode'] and self.library_thread.started: if self.library_thread is not None and settings('useDirectPaths') != self.settings['mode'] and self.library_thread.started:
self.settings['mode'] = settings('useDirectPaths') self.settings['mode'] = settings('useDirectPaths')
LOG.info("New playback mode setting: %s", self.settings['mode']) LOG.info("New playback mode setting: %s", self.settings['mode'])

View file

@ -31,7 +31,7 @@ class FullSync(object):
''' '''
# Borg - multiple instances, shared state # Borg - multiple instances, shared state
_shared_state: Dict[str, Any] = {} _shared_state: Dict[str, Any] = {}
sync = None sync = get_sync()
running = False running = False
screensaver = None screensaver = None

View file

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals from __future__ import division, absolute_import, print_function, unicode_literals
from typing import Any, Dict, List
################################################################################################## ##################################################################################################
from . import settings, LazyLogger from . import settings, LazyLogger
@ -42,7 +44,7 @@ class API(object):
return self.item['Name'] return self.item['Name']
def get_actors(self): def get_actors(self):
cast = [] cast: List[Dict[str, Any]] = []
if 'People' in self.item: if 'People' in self.item:
self.get_people_artwork(self.item['People']) self.get_people_artwork(self.item['People'])

View file

@ -6,6 +6,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
import os import os
import logging import logging
import traceback import traceback
from typing import Dict, List
from six import ensure_text from six import ensure_text
from kodi_six import xbmc, xbmcaddon from kodi_six import xbmc, xbmcaddon
@ -36,7 +37,7 @@ class LogHandler(logging.StreamHandler):
logging.StreamHandler.__init__(self) logging.StreamHandler.__init__(self)
self.setFormatter(MyFormatter()) self.setFormatter(MyFormatter())
self.sensitive = {'Token': [], 'Server': []} self.sensitive: Dict[str, List[str]] = {'Token': [], 'Server': []}
for server in database.get_credentials()['Servers']: for server in database.get_credentials()['Servers']:

View file

@ -153,7 +153,8 @@ def event(method, data=None, sender=None, hexlify=False):
xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data)) xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data))
def dialog(dialog_type, *args, **kwargs): def dialog(dialog_type: str, *args: str, **kwargs):
arg_list = list(args)
d = xbmcgui.Dialog() d = xbmcgui.Dialog()
@ -165,9 +166,8 @@ def dialog(dialog_type, *args, **kwargs):
if "heading" in kwargs: if "heading" in kwargs:
kwargs['heading'] = kwargs['heading'].replace("{jellyfin}", translate('addon_name')) kwargs['heading'] = kwargs['heading'].replace("{jellyfin}", translate('addon_name'))
if args: if arg_list:
args = list(args) arg_list[0] = arg_list[0].replace("{jellyfin}", translate('addon_name'))
args[0] = args[0].replace("{jellyfin}", translate('addon_name'))
types = { types = {
'yesno': d.yesno, 'yesno': d.yesno,
@ -178,7 +178,7 @@ def dialog(dialog_type, *args, **kwargs):
'numeric': d.numeric, 'numeric': d.numeric,
'multi': d.multiselect 'multi': d.multiselect
} }
return types[dialog_type](*args, **kwargs) return types[dialog_type](*arg_list, **kwargs)
def should_stop(): def should_stop():

View file

@ -27,7 +27,7 @@ def tvtunes_nfo(path, urls):
except Exception: except Exception:
xml = etree.Element('tvtunes') xml = etree.Element('tvtunes')
for elem in xml.getiterator('tvtunes'): for elem in xml.iter('tvtunes'):
for file in list(elem): for file in list(elem):
elem.remove(file) elem.remove(file)

View file

@ -33,7 +33,7 @@ def clean_none_dict_values(obj):
if mutable: if mutable:
# Remove keys with None value # Remove keys with None value
for key in remove: for key in remove:
item.pop(key) item.pop(key) # typing: ignore [attr-defined]
elif isinstance(item, collections_abc.Iterable): elif isinstance(item, collections_abc.Iterable):
for value in item: for value in item:

View file

@ -5,6 +5,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
import threading import threading
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Dict, List, Tuple
from six.moves import queue as Queue from six.moves import queue as Queue
@ -47,18 +48,18 @@ class Library(threading.Thread):
self.monitor = monitor self.monitor = monitor
self.player = monitor.monitor.player self.player = monitor.monitor.player
self.server = Jellyfin().get_client() self.server = Jellyfin().get_client()
self.updated_queue = Queue.Queue() self.updated_queue: Queue.Queue[str] = Queue.Queue()
self.userdata_queue = Queue.Queue() self.userdata_queue: Queue.Queue[str] = Queue.Queue()
self.removed_queue = Queue.Queue() self.removed_queue: Queue.Queue[str] = Queue.Queue()
self.updated_output = self.__new_queues__() self.updated_output = self.__new_queues__()
self.userdata_output = self.__new_queues__() self.userdata_output = self.__new_queues__()
self.removed_output = self.__new_queues__() self.removed_output = self.__new_queues__()
self.notify_output = Queue.Queue() self.notify_output: Queue.Queue[Tuple[str, str]] = Queue.Queue()
self.jellyfin_threads = [] self.jellyfin_threads = []
self.download_threads = [] self.download_threads = []
self.notify_threads = [] self.notify_threads = []
self.writer_threads = {'updated': [], 'userdata': [], 'removed': []} self.writer_threads: Dict[str, List[BaseWorker]] = {'updated': [], 'userdata': [], 'removed': []}
self.database_lock = threading.Lock() self.database_lock = threading.Lock()
self.music_database_lock = threading.Lock() self.music_database_lock = threading.Lock()
@ -222,10 +223,10 @@ class Library(threading.Thread):
''' Get items from jellyfin and place them in the appropriate queues. ''' Get items from jellyfin and place them in the appropriate queues.
''' '''
for queue in ((self.updated_queue, self.updated_output), (self.userdata_queue, self.userdata_output)): for input_queue, output_queue in ((self.updated_queue, self.updated_output), (self.userdata_queue, self.userdata_output)):
if queue[0].qsize() and len(self.download_threads) < DTHREADS: if input_queue.qsize() and len(self.download_threads) < DTHREADS:
new_thread = GetItemWorker(self.server, queue[0], queue[1]) new_thread = GetItemWorker(self.server, input_queue, output_queue)
new_thread.start() new_thread.start()
LOG.info("-->[ q:download/%s ]", id(new_thread)) LOG.info("-->[ q:download/%s ]", id(new_thread))
self.download_threads.append(new_thread) self.download_threads.append(new_thread)
@ -591,7 +592,11 @@ class Library(threading.Thread):
LOG.info("---[ removed:%s ]", len(data)) LOG.info("---[ removed:%s ]", len(data))
class UpdateWorker(threading.Thread): class BaseWorker(threading.Thread):
is_done: bool
class UpdateWorker(BaseWorker):
is_done = False is_done = False
@ -667,7 +672,7 @@ class UpdateWorker(threading.Thread):
self.is_done = True self.is_done = True
class UserDataWorker(threading.Thread): class UserDataWorker(BaseWorker):
is_done = False is_done = False
@ -730,7 +735,7 @@ class UserDataWorker(threading.Thread):
self.is_done = True self.is_done = True
class SortWorker(threading.Thread): class SortWorker(BaseWorker):
is_done = False is_done = False
@ -777,7 +782,7 @@ class SortWorker(threading.Thread):
self.is_done = True self.is_done = True
class RemovedWorker(threading.Thread): class RemovedWorker(BaseWorker):
is_done = False is_done = False
@ -838,7 +843,7 @@ class RemovedWorker(threading.Thread):
self.is_done = True self.is_done = True
class NotifyWorker(threading.Thread): class NotifyWorker(BaseWorker):
is_done = False is_done = False

View file

@ -117,11 +117,11 @@ class Monitor(xbmc.Monitor):
LOG.exception(error) LOG.exception(error)
server = Jellyfin() server = Jellyfin()
server = server.get_client() server_client = server.get_client()
if method == 'Play': if method == 'Play':
items = server.jellyfin.get_items(data['ItemIds']) items = server_client.jellyfin.get_items(data['ItemIds'])
PlaylistWorker(data.get('ServerId'), items, data['PlayCommand'] == 'PlayNow', PlaylistWorker(data.get('ServerId'), items, data['PlayCommand'] == 'PlayNow',
data.get('StartPositionTicks', 0), data.get('AudioStreamIndex'), data.get('StartPositionTicks', 0), data.get('AudioStreamIndex'),
@ -130,7 +130,7 @@ class Monitor(xbmc.Monitor):
# TODO no clue if this is called by anything # TODO no clue if this is called by anything
elif method == 'PlayPlaylist': elif method == 'PlayPlaylist':
server.jellyfin.post_session(server.config.data['app.session'], "Playing", { server_client.jellyfin.post_session(server_client.config.data['app.session'], "Playing", {
'PlayCommand': "PlayNow", 'PlayCommand': "PlayNow",
'ItemIds': data['Id'], 'ItemIds': data['Id'],
'StartPositionTicks': 0 'StartPositionTicks': 0
@ -149,14 +149,14 @@ class Monitor(xbmc.Monitor):
self.server_instance(data['ServerId']) self.server_instance(data['ServerId'])
elif method == 'AddUser': elif method == 'AddUser':
server.jellyfin.session_add_user(server.config.data['app.session'], data['Id'], data['Add']) server_client.jellyfin.session_add_user(server_client.config.data['app.session'], data['Id'], data['Add'])
self.additional_users(server) self.additional_users(server_client)
elif method == 'Player.OnPlay': elif method == 'Player.OnPlay':
on_play(data, server) on_play(data, server_client)
elif method == 'VideoLibrary.OnUpdate': elif method == 'VideoLibrary.OnUpdate':
on_update(data, server) on_update(data, server_client)
def server_instance(self, server_id=None): def server_instance(self, server_id=None):

View file

@ -1,6 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals from __future__ import division, absolute_import, print_function, unicode_literals
from abc import ABCMeta
from sqlite3 import Cursor
################################################################################################## ##################################################################################################
from ...helper import values, LazyLogger from ...helper import values, LazyLogger
@ -15,7 +18,8 @@ LOG = LazyLogger(__name__)
################################################################################################## ##################################################################################################
class Kodi(object): class Kodi(metaclass=ABCMeta):
cursor: Cursor
def __init__(self): def __init__(self):
self.artwork = artwork.Artwork(self.cursor) self.artwork = artwork.Artwork(self.cursor)

View file

@ -4,6 +4,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
################################################################################################## ##################################################################################################
import datetime import datetime
from typing import List
from ..database import jellyfin_db, queries as QUEM from ..database import jellyfin_db, queries as QUEM
from ..helper import api, stop, validate, jellyfin_item, values, Local, LazyLogger from ..helper import api, stop, validate, jellyfin_item, values, Local, LazyLogger
@ -551,7 +552,7 @@ class Music(KodiDb):
''' Get all child elements from tv show jellyfin id. ''' Get all child elements from tv show jellyfin id.
''' '''
obj = {'Id': item_id} obj = {'Id': item_id}
child = [] child: List[str] = []
try: try:
obj['KodiId'] = e_item[0] obj['KodiId'] = e_item[0]

View file

@ -5,6 +5,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
import datetime import datetime
import re import re
from typing import List
from six.moves.urllib.parse import urlencode from six.moves.urllib.parse import urlencode
from kodi_six.utils import py2_encode from kodi_six.utils import py2_encode
@ -122,7 +123,7 @@ class MusicVideos(KodiDb):
if search: if search:
obj['Index'] = search.group() obj['Index'] = search.group()
tags = [] tags: List[str] = []
tags.extend(obj['Tags'] or []) tags.extend(obj['Tags'] or [])
tags.append(obj['LibraryName']) tags.append(obj['LibraryName'])

View file

@ -5,6 +5,7 @@ from __future__ import division, absolute_import, print_function, unicode_litera
import sqlite3 import sqlite3
from ntpath import dirname from ntpath import dirname
from typing import List
from six.moves.urllib.parse import urlencode from six.moves.urllib.parse import urlencode
from kodi_six.utils import py2_encode from kodi_six.utils import py2_encode
@ -101,7 +102,7 @@ class TVShows(KodiDb):
if obj['Premiere']: if obj['Premiere']:
obj['Premiere'] = str(Local(obj['Premiere'])).split('.')[0].replace('T', " ") obj['Premiere'] = str(Local(obj['Premiere'])).split('.')[0].replace('T', " ")
tags = [] tags: List[str] = []
tags.extend(obj['Tags'] or []) tags.extend(obj['Tags'] or [])
tags.append(obj['LibraryName']) tags.append(obj['LibraryName'])
@ -623,7 +624,7 @@ class TVShows(KodiDb):
''' Get all child elements from tv show jellyfin id. ''' Get all child elements from tv show jellyfin id.
''' '''
obj = {'Id': item_id} obj = {'Id': item_id}
child = [] child: List[str] = []
try: try:
obj['KodiId'] = e_item[0] obj['KodiId'] = e_item[0]

4
mypy.ini Normal file
View file

@ -0,0 +1,4 @@
[mypy]
check_untyped_defs = True
warn_unused_configs = True
files = .