Commit ad13883c authored by Marinus Schraal's avatar Marinus Schraal

CI: Add static type checking pass

Also:
* Ignore initial property errors
* Add relevant .gitignore
* Add some required types
* Add some info to the README
parent 6dd7884f
......@@ -12,6 +12,7 @@ builddir/
/.dirstamp
/.gitignore
/.libs
/.mypy_cache
/AUTHORS
/ABOUT-NLS
/GPATH
......
......@@ -28,3 +28,9 @@ flake8:
script:
- dnf install -y python3-flake8
- flake8 --ignore E402,W503 --show-source gnomemusic/
mypy:
stage: check
script:
- dnf install -y python3-mypy
- mypy --ignore-missing-imports --disallow-incomplete-defs gnomemusic
......@@ -101,6 +101,42 @@ All non-public classwide variables or methods should be prepended with an unders
_single_leading_underscore: weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an underscore.
>>>
### Type checking
Post 3.38 Music is starting to use type checking for all new code. This means that all arguments, returns values and variables have defined types and these types are checked for errors during the CI phase. Music uses [mypy](http://www.mypy-lang.org/) for the type checking pass.
The specific syntax is best learned from the code already adapted ([coresong.py](gnomemusic/coresong.py), [grltrackerwrapper.py](gnomemusic/grilowrappers/grltrackerwrapper.py)) or online sources, note that Music uses the annotation style. A simple example follows.
###### Old
```python
x = []
x.append(1)
```
###### New
```python
from typing import List
x: List[int] = []
x.append(1)
```
#### Properties
Mypy does not currently support PyGObject properties. This means property setters need to be forceibly ignored.
```python
@GObject.Property(type=bool, default=False)
def selected(self) -> bool:
return self._selected
@selected.setter # type: ignore
def selected(self, value: bool) -> None:
self._selected = value
```
### PyGObject specifics
#### Treemodel
......
......@@ -24,6 +24,7 @@
from enum import Enum
from math import pi
from typing import Dict, Tuple
import cairo
from gi.repository import Gdk, GdkPixbuf, Gio, Gtk, GLib, GObject
......@@ -32,6 +33,7 @@ from gnomemusic.corealbum import CoreAlbum
from gnomemusic.coreartist import CoreArtist
from gnomemusic.coresong import CoreSong
from gnomemusic.musiclogger import MusicLogger
from gnomemusic.utils import ArtSize
def _make_icon_frame(
......@@ -128,7 +130,9 @@ class DefaultIcon(GObject.GObject):
LOADING = "content-loading-symbolic"
MUSIC = "folder-music-symbolic"
_cache = {}
_cache: Dict[
Tuple["DefaultIcon.Type", ArtSize, int, bool], cairo.Surface] = {}
_default_theme = Gtk.IconTheme.get_default()
def __init__(self):
......
......@@ -118,7 +118,7 @@ class CoreAlbum(GObject.GObject):
def selected(self):
return self._selected
@selected.setter
@selected.setter # type: ignore
def selected(self, value):
if value == self._selected:
return
......@@ -145,7 +145,7 @@ class CoreAlbum(GObject.GObject):
return self._thumbnail
@thumbnail.setter
@thumbnail.setter # type: ignore
def thumbnail(self, value):
"""Album art thumbnail setter
......
......@@ -93,7 +93,7 @@ class CoreArtist(GObject.GObject):
def selected(self):
return self._selected
@selected.setter
@selected.setter # type: ignore
def selected(self, value):
if value == self._selected:
return
......@@ -120,7 +120,7 @@ class CoreArtist(GObject.GObject):
return self._thumbnail
@thumbnail.setter
@thumbnail.setter # type: ignore
def thumbnail(self, value):
"""Artist art thumbnail setter
......
......@@ -113,7 +113,7 @@ class CoreDisc(GObject.GObject):
def selected(self):
return self._selected
@selected.setter
@selected.setter # type: ignore
def selected(self, value):
self._selected = value
......
......@@ -311,7 +311,7 @@ class CoreModel(GObject.GObject):
"""
return self._active_core_object
@active_core_object.setter
@active_core_object.setter # type: ignore
def active_core_object(self, value):
"""Set the current playing core object
(album, artist, playlist, search result or song).
......
......@@ -89,7 +89,7 @@ class CoreSong(GObject.GObject):
def favorite(self):
return self._favorite
@favorite.setter
@favorite.setter # type: ignore
def favorite(self, favorite):
if not self._is_tracker:
return
......@@ -109,7 +109,7 @@ class CoreSong(GObject.GObject):
def selected(self):
return self._selected
@selected.setter
@selected.setter # type: ignore
def selected(self, value):
if not self._is_tracker:
return
......@@ -133,7 +133,7 @@ class CoreSong(GObject.GObject):
return self._thumbnail
@thumbnail.setter
@thumbnail.setter # type: ignore
def thumbnail(self, value):
"""Song art thumbnail setter
......
......@@ -325,7 +325,7 @@ class Playlist(GObject.GObject):
return self._model
@model.setter
@model.setter # type: ignore
def model(self, value):
self._model = value
......@@ -432,7 +432,7 @@ class Playlist(GObject.GObject):
"""
return self._title
@title.setter
@title.setter # type: ignore
def title(self, new_name):
"""Rename a playlist
......
......@@ -134,7 +134,7 @@ class GrlTrackerWrapper(GObject.GObject):
def source(self):
return self._source
@source.setter
@source.setter # type: ignore
def source(self, new_source):
"""Set a new grilo tracker source
......
......@@ -215,7 +215,7 @@ class GstPlayer(GObject.GObject):
"""
return self._state
@state.setter
@state.setter # type: ignore
def state(self, state):
"""Set state of the player
......@@ -239,7 +239,7 @@ class GstPlayer(GObject.GObject):
"""
return self._player.props.current_uri
@url.setter
@url.setter # type: ignore
def url(self, url_):
"""url to load next
......@@ -274,7 +274,7 @@ class GstPlayer(GObject.GObject):
# Setter provided to trigger a property signal.
# For internal use only.
@duration.setter
@duration.setter # type: ignore
def duration(self, duration):
"""Set duration of current media (internal)
......
......@@ -585,7 +585,7 @@ class Player(GObject.GObject):
def repeat_mode(self):
return self._repeat
@repeat_mode.setter
@repeat_mode.setter # type: ignore
def repeat_mode(self, mode):
if mode == self._repeat:
return
......
......@@ -274,7 +274,7 @@ class LastFmScrobbler(GObject.GObject):
"""
return self._account_state
@account_state.setter
@account_state.setter # type: ignore
def account_state(self, value):
"""Set the Last.fm account state
......@@ -298,7 +298,7 @@ class LastFmScrobbler(GObject.GObject):
return (self.props.account_state == GoaLastFM.State.ENABLED
and self._report is True)
@can_scrobble.setter
@can_scrobble.setter # type: ignore
def can_scrobble(self, value):
"""Set the can_scrobble status
......@@ -324,7 +324,7 @@ class LastFmScrobbler(GObject.GObject):
"""Bool indicating current scrobble status"""
return self._scrobbled
@scrobbled.setter
@scrobbled.setter # type: ignore
def scrobbled(self, scrobbled):
self._scrobbled = scrobbled
......
......@@ -175,7 +175,7 @@ class ArtistsView(Gtk.Box):
"""
return self._selection_mode
@selection_mode.setter
@selection_mode.setter # type: ignore
def selection_mode(self, value):
"""selection-mode setter
......
......@@ -89,7 +89,7 @@ class EmptyView(Gtk.Stack):
"""
return self._state
@state.setter
@state.setter # type: ignore
def state(self, value):
"""Set the state of the empty view
......
......@@ -474,7 +474,7 @@ class SearchView(Gtk.Stack):
"""
return self._search_mode_active
@search_mode_active.setter
@search_mode_active.setter # type: ignore
def search_mode_active(self, value):
"""Set search mode status.
......
......@@ -113,7 +113,7 @@ class SongsView(Gtk.ScrolledWindow):
"""
return self._selection_mode
@selection_mode.setter
@selection_mode.setter # type: ignore
def selection_mode(self, value):
"""selection-mode setter
......
......@@ -73,7 +73,7 @@ class ArtStack(Gtk.Stack):
"""
return self._size
@size.setter
@size.setter # type: ignore
def size(self, value):
"""Set the cover size
......@@ -86,7 +86,7 @@ class ArtStack(Gtk.Stack):
def coreobject(self):
return self._coreobject
@coreobject.setter
@coreobject.setter # type: ignore
def coreobject(self, coreobject):
if self._thumbnail_id != 0:
self._coreobject.disconnect(self._thumbnail_id)
......
......@@ -55,7 +55,7 @@ class SelectionBarMenuButton(Gtk.MenuButton):
"""
return self._selected_songs_count
@selected_songs_count.setter
@selected_songs_count.setter # type: ignore
def selected_songs_count(self, value):
"""Set the number of songs selected
......@@ -157,7 +157,7 @@ class HeaderBar(Gtk.HeaderBar):
"""
return self._selection_mode
@selection_mode.setter
@selection_mode.setter # type: ignore
def selection_mode(self, mode):
"""Set the selection mode
......@@ -182,7 +182,7 @@ class HeaderBar(Gtk.HeaderBar):
"""
return self._state
@state.setter
@state.setter # type: ignore
def state(self, value):
"""Set state of the of widget
......
......@@ -83,7 +83,7 @@ class PlayerToolbar(Gtk.ActionBar):
"""
return self._player
@player.setter
@player.setter # type: ignore
def player(self, player):
"""Set the GstPlayer object used
......
......@@ -70,7 +70,7 @@ class PlaylistControls(Gtk.Grid):
"""
return self._application
@application.setter
@application.setter # type: ignore
def application(self, application):
"""Set the Application object used
......@@ -157,7 +157,7 @@ class PlaylistControls(Gtk.Grid):
"""
return self._playlist
@playlist.setter
@playlist.setter # type: ignore
def playlist(self, new_playlist):
"""Playlist property setter.
......
......@@ -112,7 +112,7 @@ class SearchHeaderBar(Gtk.HeaderBar):
"""
return self._selection_mode
@selection_mode.setter
@selection_mode.setter # type: ignore
def selection_mode(self, mode):
"""Set the selection mode
......@@ -137,7 +137,7 @@ class SearchHeaderBar(Gtk.HeaderBar):
"""
return self._state
@state.setter
@state.setter # type: ignore
def state(self, value):
"""Set state of the of widget
......
......@@ -64,7 +64,7 @@ class SmoothScale(Gtk.Scale):
"""
return self._player
@player.setter
@player.setter # type: ignore
def player(self, player):
"""Set the Player object used
......
......@@ -234,7 +234,7 @@ class SongWidget(Gtk.EventBox):
"""
return self._selection_mode
@selection_mode.setter
@selection_mode.setter # type: ignore
def selection_mode(self, value):
"""Set the selection mode
......@@ -262,7 +262,7 @@ class SongWidget(Gtk.EventBox):
"""
return self._state
@state.setter
@state.setter # type: ignore
def state(self, value):
"""Set state of the of widget
......@@ -308,7 +308,7 @@ class SongWidget(Gtk.EventBox):
"""
return self._number_label.props.label
@song_number.setter
@song_number.setter # type: ignore
def song_number(self, new_nr):
"""Set song number label from an integer
......
......@@ -81,7 +81,7 @@ class CellRendererStar(Gtk.CellRendererPixbuf):
def show_star(self):
return self._show_star
@show_star.setter
@show_star.setter # type: ignore
def show_star(self, value):
"""Set the show-star value
......
......@@ -47,7 +47,7 @@ class StarImage(Gtk.Image):
"""
return self._favorite
@favorite.setter
@favorite.setter # type: ignore
def favorite(self, value):
"""Set favorite
......@@ -66,7 +66,7 @@ class StarImage(Gtk.Image):
def hover(self):
return self._hover
@hover.setter
@hover.setter # type: ignore
def hover(self, value):
if value:
self.set_state_flags(Gtk.StateFlags.PRELIGHT, False)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment