Tighter mypy testing, fixed up type hints
This commit is contained in:
parent
2394327d38
commit
5f3119be1f
@ -15,7 +15,7 @@ class DatabaseManager:
|
|||||||
|
|
||||||
__instance = None
|
__instance = None
|
||||||
|
|
||||||
def __init__(self, database_url: str, **kwargs):
|
def __init__(self, database_url: str, **kwargs: dict) -> None:
|
||||||
if DatabaseManager.__instance is None:
|
if DatabaseManager.__instance is None:
|
||||||
self.db = Alchemical(database_url, **kwargs)
|
self.db = Alchemical(database_url, **kwargs)
|
||||||
self.db.create_all()
|
self.db.create_all()
|
||||||
@ -24,7 +24,7 @@ class DatabaseManager:
|
|||||||
raise Exception("Attempted to create a second DatabaseManager instance")
|
raise Exception("Attempted to create a second DatabaseManager instance")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_instance(database_url: str, **kwargs):
|
def get_instance(database_url: str, **kwargs: dict) -> Alchemical:
|
||||||
if DatabaseManager.__instance is None:
|
if DatabaseManager.__instance is None:
|
||||||
DatabaseManager(database_url, **kwargs)
|
DatabaseManager(database_url, **kwargs)
|
||||||
return DatabaseManager.__instance
|
return DatabaseManager.__instance
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from PyQt6.QtWidgets import (
|
|||||||
QListWidgetItem,
|
QListWidgetItem,
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
QTableWidgetItem,
|
QTableWidgetItem,
|
||||||
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Third party imports
|
# Third party imports
|
||||||
@ -39,10 +40,10 @@ class ReplaceFilesDialog(QDialog):
|
|||||||
self,
|
self,
|
||||||
session: Session,
|
session: Session,
|
||||||
main_window: QMainWindow,
|
main_window: QMainWindow,
|
||||||
*args,
|
*args: Qt.WindowType,
|
||||||
**kwargs,
|
**kwargs: Qt.WindowType,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(main_window, *args, **kwargs)
|
||||||
self.session = session
|
self.session = session
|
||||||
self.main_window = main_window
|
self.main_window = main_window
|
||||||
self.ui = dlg_replace_files_ui.Ui_Dialog()
|
self.ui = dlg_replace_files_ui.Ui_Dialog()
|
||||||
@ -232,18 +233,19 @@ class TrackSelectDialog(QDialog):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
parent: QMainWindow,
|
||||||
session: Session,
|
session: Session,
|
||||||
new_row_number: int,
|
new_row_number: int,
|
||||||
source_model: PlaylistModel,
|
source_model: PlaylistModel,
|
||||||
add_to_header: Optional[bool] = False,
|
add_to_header: Optional[bool] = False,
|
||||||
*args,
|
*args: Qt.WindowType,
|
||||||
**kwargs,
|
**kwargs: Qt.WindowType,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Subclassed QDialog to manage track selection
|
Subclassed QDialog to manage track selection
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(parent, *args, **kwargs)
|
||||||
self.session = session
|
self.session = session
|
||||||
self.new_row_number = new_row_number
|
self.new_row_number = new_row_number
|
||||||
self.source_model = source_model
|
self.source_model = source_model
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
import urllib.parse
|
import urllib.parse
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
from slugify import slugify # type: ignore
|
from slugify import slugify # type: ignore
|
||||||
from typing import Dict
|
from typing import Dict, Optional
|
||||||
|
|
||||||
# PyQt imports
|
# PyQt imports
|
||||||
from PyQt6.QtCore import QUrl # type: ignore
|
from PyQt6.QtCore import QUrl
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||||
from PyQt6.QtWidgets import QTabWidget
|
from PyQt6.QtWidgets import QTabWidget, QWidget
|
||||||
|
|
||||||
# Third party imports
|
# Third party imports
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ class InfoTabs(QTabWidget):
|
|||||||
Class to manage info tabs
|
Class to manage info tabs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent=None) -> None:
|
def __init__(self, parent: Optional[QWidget] = None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
|
|
||||||
self.signals = MusicMusterSignals()
|
self.signals = MusicMusterSignals()
|
||||||
|
|||||||
@ -19,7 +19,7 @@ from config import Config
|
|||||||
class LevelTagFilter(logging.Filter):
|
class LevelTagFilter(logging.Filter):
|
||||||
"""Add leveltag"""
|
"""Add leveltag"""
|
||||||
|
|
||||||
def filter(self, record: logging.LogRecord):
|
def filter(self, record: logging.LogRecord) -> bool:
|
||||||
# Extract the first character of the level name
|
# Extract the first character of the level name
|
||||||
record.leveltag = record.levelname[0]
|
record.leveltag = record.levelname[0]
|
||||||
|
|
||||||
|
|||||||
@ -110,7 +110,7 @@ class Playdates(dbtables.PlaydatesTable):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def last_playdates(
|
def last_playdates(
|
||||||
session: Session, track_id: int, limit=5
|
session: Session, track_id: int, limit: int = 5
|
||||||
) -> Sequence["Playdates"]:
|
) -> Sequence["Playdates"]:
|
||||||
"""
|
"""
|
||||||
Return a list of the last limit playdates for this track, sorted
|
Return a list of the last limit playdates for this track, sorted
|
||||||
@ -143,7 +143,7 @@ class Playdates(dbtables.PlaydatesTable):
|
|||||||
return Config.EPOCH # pragma: no cover
|
return Config.EPOCH # pragma: no cover
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def last_played_tracks(session: Session, limit=5) -> Sequence["Playdates"]:
|
def last_played_tracks(session: Session, limit: int = 5) -> Sequence["Playdates"]:
|
||||||
"""
|
"""
|
||||||
Return a list of the last limit tracks played, sorted
|
Return a list of the last limit tracks played, sorted
|
||||||
earliest to latest.
|
earliest to latest.
|
||||||
@ -628,7 +628,7 @@ class Tracks(dbtables.TracksTable):
|
|||||||
raise ValueError(error)
|
raise ValueError(error)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_all(cls, session) -> List["Tracks"]:
|
def get_all(cls, session: Session) -> Sequence["Tracks"]:
|
||||||
"""Return a list of all tracks"""
|
"""Return a list of all tracks"""
|
||||||
|
|
||||||
return session.scalars(select(cls)).unique().all()
|
return session.scalars(select(cls)).unique().all()
|
||||||
|
|||||||
@ -37,6 +37,7 @@ from PyQt6.QtWidgets import (
|
|||||||
QListWidgetItem,
|
QListWidgetItem,
|
||||||
QMainWindow,
|
QMainWindow,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Third party imports
|
# Third party imports
|
||||||
@ -257,7 +258,7 @@ class PreviewManager:
|
|||||||
|
|
||||||
|
|
||||||
class Window(QMainWindow, Ui_MainWindow):
|
class Window(QMainWindow, Ui_MainWindow):
|
||||||
def __init__(self, parent=None, *args, **kwargs) -> None:
|
def __init__(self, parent: Optional[QWidget] = None, *args: list, **kwargs: dict) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
@ -866,6 +867,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
|||||||
)
|
)
|
||||||
with db.Session() as session:
|
with db.Session() as session:
|
||||||
dlg = TrackSelectDialog(
|
dlg = TrackSelectDialog(
|
||||||
|
parent=self,
|
||||||
session=session,
|
session=session,
|
||||||
new_row_number=new_row_number,
|
new_row_number=new_row_number,
|
||||||
source_model=self.active_proxy_model(),
|
source_model=self.active_proxy_model(),
|
||||||
|
|||||||
@ -70,6 +70,7 @@ Released under terms of the GNU General Public License version 2:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from io import TextIOWrapper
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
@ -77,6 +78,7 @@ import time
|
|||||||
import errno
|
import errno
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
if sys.version_info[0] < 3:
|
||||||
raise RuntimeError("PipeClient Error: Python 3.x required")
|
raise RuntimeError("PipeClient Error: Python 3.x required")
|
||||||
@ -135,11 +137,11 @@ class PipeClient:
|
|||||||
self.__dict__ = cls._shared_state
|
self.__dict__ = cls._shared_state
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.timer: bool = False # type: ignore
|
self.timer: bool = False
|
||||||
self._start_time: float = 0 # type: ignore
|
self._start_time: float = 0
|
||||||
self._write_pipe = None
|
self._write_pipe: Optional[TextIOWrapper] = None
|
||||||
self.reply: str = "" # type: ignore
|
self.reply: str = ""
|
||||||
if not self._write_pipe:
|
if not self._write_pipe:
|
||||||
self._write_thread_start()
|
self._write_thread_start()
|
||||||
self._read_thread_start()
|
self._read_thread_start()
|
||||||
@ -166,7 +168,7 @@ class PipeClient:
|
|||||||
read_thread.daemon = True
|
read_thread.daemon = True
|
||||||
read_thread.start()
|
read_thread.start()
|
||||||
|
|
||||||
def write(self, command, timer=False) -> None:
|
def write(self, command: str, timer: Optional[bool] = False) -> None:
|
||||||
"""Write a command to _write_pipe.
|
"""Write a command to _write_pipe.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -181,7 +183,13 @@ class PipeClient:
|
|||||||
write("GetInfo: Type=Labels", timer=True):
|
write("GetInfo: Type=Labels", timer=True):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.timer = timer
|
|
||||||
|
# If write pipe not defined, return
|
||||||
|
if self._write_pipe is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if timer:
|
||||||
|
self.timer = timer
|
||||||
self._write_pipe.write(command + EOL)
|
self._write_pipe.write(command + EOL)
|
||||||
# Check that read pipe is alive
|
# Check that read pipe is alive
|
||||||
if PipeClient.reader_pipe_broken.is_set():
|
if PipeClient.reader_pipe_broken.is_set():
|
||||||
@ -240,7 +248,7 @@ class PipeClient:
|
|||||||
return self.reply
|
return self.reply
|
||||||
|
|
||||||
|
|
||||||
def bool_from_string(strval) -> bool:
|
def bool_from_string(strval: str) -> bool:
|
||||||
"""Return boolean value from string"""
|
"""Return boolean value from string"""
|
||||||
if strval.lower() in ("true", "t", "1", "yes", "y"):
|
if strval.lower() in ("true", "t", "1", "yes", "y"):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import re
|
|||||||
from PyQt6.QtCore import (
|
from PyQt6.QtCore import (
|
||||||
QAbstractTableModel,
|
QAbstractTableModel,
|
||||||
QModelIndex,
|
QModelIndex,
|
||||||
|
QObject,
|
||||||
QRegularExpression,
|
QRegularExpression,
|
||||||
QSortFilterProxyModel,
|
QSortFilterProxyModel,
|
||||||
Qt,
|
Qt,
|
||||||
@ -113,9 +114,9 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
playlist_id: int,
|
playlist_id: int,
|
||||||
*args,
|
*args: Optional[QObject],
|
||||||
**kwargs,
|
**kwargs: Optional[QObject],
|
||||||
):
|
) -> None:
|
||||||
log.debug(f"PlaylistModel.__init__({playlist_id=})")
|
log.debug(f"PlaylistModel.__init__({playlist_id=})")
|
||||||
|
|
||||||
self.playlist_id = playlist_id
|
self.playlist_id = playlist_id
|
||||||
@ -309,7 +310,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):
|
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole) -> QVariant:
|
||||||
"""Return data to view"""
|
"""Return data to view"""
|
||||||
|
|
||||||
if not index.isValid() or not (0 <= index.row() < len(self.playlist_rows)):
|
if not index.isValid() or not (0 <= index.row() < len(self.playlist_rows)):
|
||||||
@ -330,7 +331,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if role in dispatch_table:
|
if role in dispatch_table:
|
||||||
return dispatch_table[role](row, column, prd)
|
return QVariant(dispatch_table[role](row, column, prd))
|
||||||
|
|
||||||
# Document other roles but don't use them
|
# Document other roles but don't use them
|
||||||
if role in [
|
if role in [
|
||||||
@ -1081,7 +1082,7 @@ class PlaylistModel(QAbstractTableModel):
|
|||||||
# Update display
|
# Update display
|
||||||
self.invalidate_row(track_sequence.previous.row_number)
|
self.invalidate_row(track_sequence.previous.row_number)
|
||||||
|
|
||||||
def refresh_data(self, session: db.session):
|
def refresh_data(self, session: db.session) -> None:
|
||||||
"""Populate dicts for data calls"""
|
"""Populate dicts for data calls"""
|
||||||
|
|
||||||
# Populate self.playlist_rows with playlist data
|
# Populate self.playlist_rows with playlist data
|
||||||
@ -1500,9 +1501,9 @@ class PlaylistProxyModel(QSortFilterProxyModel):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
source_model: PlaylistModel,
|
source_model: PlaylistModel,
|
||||||
*args,
|
*args: QObject,
|
||||||
**kwargs,
|
**kwargs: QObject,
|
||||||
):
|
) -> None:
|
||||||
self.source_model = source_model
|
self.source_model = source_model
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,7 @@ class EscapeDelegate(QStyledItemDelegate):
|
|||||||
- checks with user before abandoning edit on Escape
|
- checks with user before abandoning edit on Escape
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, parent, source_model: PlaylistModel) -> None:
|
def __init__(self, parent: QWidget, source_model: PlaylistModel) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.source_model = source_model
|
self.source_model = source_model
|
||||||
self.signals = MusicMusterSignals()
|
self.signals = MusicMusterSignals()
|
||||||
@ -70,7 +70,7 @@ class EscapeDelegate(QStyledItemDelegate):
|
|||||||
parent: Optional[QWidget],
|
parent: Optional[QWidget],
|
||||||
option: QStyleOptionViewItem,
|
option: QStyleOptionViewItem,
|
||||||
index: QModelIndex,
|
index: QModelIndex,
|
||||||
):
|
) -> Optional[QWidget]:
|
||||||
"""
|
"""
|
||||||
Intercept createEditor call and make row just a little bit taller
|
Intercept createEditor call and make row just a little bit taller
|
||||||
"""
|
"""
|
||||||
@ -378,6 +378,7 @@ class PlaylistTab(QTableView):
|
|||||||
|
|
||||||
with db.Session() as session:
|
with db.Session() as session:
|
||||||
dlg = TrackSelectDialog(
|
dlg = TrackSelectDialog(
|
||||||
|
parent=self.musicmuster,
|
||||||
session=session,
|
session=session,
|
||||||
new_row_number=model_row_number,
|
new_row_number=model_row_number,
|
||||||
source_model=self.source_model,
|
source_model=self.source_model,
|
||||||
|
|||||||
@ -113,7 +113,7 @@ class _FadeCurve:
|
|||||||
if self.curve:
|
if self.curve:
|
||||||
self.curve.setPen(Config.FADE_CURVE_FOREGROUND)
|
self.curve.setPen(Config.FADE_CURVE_FOREGROUND)
|
||||||
|
|
||||||
def tick(self, play_time) -> None:
|
def tick(self, play_time: int) -> None:
|
||||||
"""Update volume fade curve"""
|
"""Update volume fade curve"""
|
||||||
|
|
||||||
if not self.GraphWidget:
|
if not self.GraphWidget:
|
||||||
@ -136,10 +136,10 @@ class _FadeCurve:
|
|||||||
|
|
||||||
|
|
||||||
class _FadeTrack(QRunnable):
|
class _FadeTrack(QRunnable):
|
||||||
def __init__(self, player: vlc.MediaPlayer, fade_seconds) -> None:
|
def __init__(self, player: vlc.MediaPlayer, fade_seconds: int) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.player: vlc.MediaPlayer = player
|
self.player = player
|
||||||
self.fade_seconds: int = fade_seconds
|
self.fade_seconds = fade_seconds
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -172,11 +172,11 @@ class _Music:
|
|||||||
Manage the playing of music tracks
|
Manage the playing of music tracks
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name) -> None:
|
def __init__(self, name: str) -> None:
|
||||||
self.VLC = vlc.Instance()
|
self.VLC = vlc.Instance()
|
||||||
self.VLC.set_user_agent(name, name)
|
self.VLC.set_user_agent(name, name)
|
||||||
self.player: Optional[vlc.MediaPlayer] = None
|
self.player: Optional[vlc.MediaPlayer] = None
|
||||||
self.name: str = name
|
self.name = name
|
||||||
self.max_volume: int = Config.VLC_VOLUME_DEFAULT
|
self.max_volume: int = Config.VLC_VOLUME_DEFAULT
|
||||||
self.start_dt: Optional[dt.datetime] = None
|
self.start_dt: Optional[dt.datetime] = None
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ from log import log
|
|||||||
from models import Tracks
|
from models import Tracks
|
||||||
|
|
||||||
|
|
||||||
def check_db(session: Session):
|
def check_db(session: Session) -> None:
|
||||||
"""
|
"""
|
||||||
Database consistency check.
|
Database consistency check.
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ def check_db(session: Session):
|
|||||||
print("There were more paths than listed that were not found")
|
print("There were more paths than listed that were not found")
|
||||||
|
|
||||||
|
|
||||||
def update_bitrates(session: Session):
|
def update_bitrates(session: Session) -> None:
|
||||||
"""
|
"""
|
||||||
Update bitrates on all tracks in database
|
Update bitrates on all tracks in database
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -52,6 +52,9 @@ build-backend = "poetry.core.masonry.api"
|
|||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
mypy_path = "/home/kae/git/musicmuster/app"
|
mypy_path = "/home/kae/git/musicmuster/app"
|
||||||
explicit_package_bases = true
|
explicit_package_bases = true
|
||||||
|
python_version = 3.11
|
||||||
|
warn_unused_configs = true
|
||||||
|
disallow_incomplete_defs = true
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
addopts = "--exitfirst --showlocals --capture=no"
|
addopts = "--exitfirst --showlocals --capture=no"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user