Got things to a good state that can be built off of
This commit is contained in:
3
Pipfile
3
Pipfile
@@ -11,7 +11,7 @@ flake8-comprehensions = "*"
|
||||
flake8-pep3101 = "*"
|
||||
flake8-print = "*"
|
||||
graphviz = "*"
|
||||
jedi = "*"
|
||||
jedi = "<0.16"
|
||||
lxml = "*"
|
||||
mypy = "*"
|
||||
pytest = "*"
|
||||
@@ -19,7 +19,6 @@ pytest-cov = "*"
|
||||
rope = "*"
|
||||
rst2html5 = "*"
|
||||
sphinx = "*"
|
||||
sphinx-autodoc-typehints = "*"
|
||||
sphinx-rtd-theme = "*"
|
||||
termcolor = "*"
|
||||
yapf = "*"
|
||||
|
16
Pipfile.lock
generated
16
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "1f998ec38046cff69f63ed51610a1ca33bef37635020695781f57684daa9da01"
|
||||
"sha256": "ec62e729c70d9ce38576ae97cfdd88b0a006886cbca1fa4ff0160383e96453a6"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -447,11 +447,11 @@
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:cd60c93b71944d628ccac47df9a60fec53150de53d42dc10a7fc4b5ba6aae798",
|
||||
"sha256:df40c97641cb943661d2db4c33c2e1ff75d491189423249e989bcea4464f3030"
|
||||
"sha256:1349c1e8c107095a55386628bb3b2a79422f3a2cab8381e34ce19909e0cf5064",
|
||||
"sha256:e909527104a903606dd63bea6e8e888833f0ef087057829b89a18364a856f807"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.17.0"
|
||||
"version": "==0.15.2"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
@@ -694,14 +694,6 @@
|
||||
"index": "pypi",
|
||||
"version": "==3.0.3"
|
||||
},
|
||||
"sphinx-autodoc-typehints": {
|
||||
"hashes": [
|
||||
"sha256:27c9e6ef4f4451766ab8d08b2d8520933b97beb21c913f3df9ab2e59b56e6c6c",
|
||||
"sha256:a6b3180167479aca2c4d1ed3b5cb044a70a76cccd6b38662d39288ebd9f0dff0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.10.3"
|
||||
},
|
||||
"sphinx-rtd-theme": {
|
||||
"hashes": [
|
||||
"sha256:00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4",
|
||||
|
@@ -286,6 +286,13 @@ def generate_class_for_type(type_name: str) -> str:
|
||||
indent_str = ' {}'
|
||||
if not has_properties:
|
||||
code.append(indent_str.format('pass'))
|
||||
else:
|
||||
code.append('')
|
||||
code.append(
|
||||
indent_str.format(
|
||||
'def get(self, key: str, default: Any = None) -> Any:'))
|
||||
code.append(
|
||||
indent_str.format(' return getattr(self, key, default)'))
|
||||
|
||||
return '\n'.join(code)
|
||||
|
||||
@@ -304,7 +311,7 @@ with open(output_file, 'w+') as outfile:
|
||||
'from dataclasses import dataclass, field',
|
||||
'from datetime import datetime',
|
||||
'from enum import Enum',
|
||||
'from typing import List, Optional',
|
||||
'from typing import Any, List, Optional',
|
||||
'',
|
||||
'from sublime.server.api_object import APIObject',
|
||||
*map(generate_class_for_type, output_order),
|
||||
|
@@ -34,7 +34,7 @@ release = f'v{sublime.__version__}'
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx_autodoc_typehints',
|
||||
'sphinx.ext.autosectionlabel',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.viewcode',
|
||||
@@ -46,6 +46,10 @@ autodoc_default_options = {
|
||||
'show-inheritance': True,
|
||||
'special-members': '__init__',
|
||||
}
|
||||
autosectionlabel_prefix_document = True
|
||||
intersphinx_mapping = {
|
||||
'python': ('https://docs.python.org/3', None),
|
||||
}
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
@@ -2,6 +2,7 @@
|
||||
ignore = E402, W503, ANN002, ANN003, ANN101, ANN102, ANN204
|
||||
exclude = .git,__pycache__,build,dist,flatpak
|
||||
suppress-none-returning = True
|
||||
suppress-dummy-args = True
|
||||
application-import-names = sublime
|
||||
import-order-style = edited
|
||||
|
||||
|
@@ -451,7 +451,7 @@ class SublimeMusicApp(Gtk.Application):
|
||||
@dbus_propagate()
|
||||
def on_refresh_window(
|
||||
self,
|
||||
_: Any,
|
||||
_,
|
||||
state_updates: Dict[str, Any],
|
||||
force: bool = False,
|
||||
):
|
||||
@@ -686,7 +686,7 @@ class SublimeMusicApp(Gtk.Application):
|
||||
# Update the window according to the new server configuration.
|
||||
self.update_window()
|
||||
|
||||
def on_stack_change(self, stack: Gtk.Stack, _: Any):
|
||||
def on_stack_change(self, stack: Gtk.Stack, _):
|
||||
self.app_config.state.current_tab = stack.get_visible_child_name()
|
||||
self.update_window()
|
||||
|
||||
@@ -815,7 +815,7 @@ class SublimeMusicApp(Gtk.Application):
|
||||
self.update_window()
|
||||
|
||||
@dbus_propagate()
|
||||
def on_volume_change(self, _: Any, value: float):
|
||||
def on_volume_change(self, _, value: float):
|
||||
self.app_config.state.volume = value
|
||||
self.player.volume = self.app_config.state.volume
|
||||
self.update_window()
|
||||
|
@@ -368,7 +368,8 @@ class CacheManager(metaclass=Singleton):
|
||||
meta_json = json.load(f)
|
||||
except json.decoder.JSONDecodeError:
|
||||
# Just continue with the default meta_json.
|
||||
pass
|
||||
logging.warning(
|
||||
'Unable to load cache', stack_info=True)
|
||||
|
||||
cache_version = meta_json.get('version', 0)
|
||||
|
||||
@@ -411,7 +412,6 @@ class CacheManager(metaclass=Singleton):
|
||||
('artist_details', ArtistWithAlbumsID3, dict),
|
||||
('artist_infos', ArtistInfo2, dict),
|
||||
]
|
||||
return
|
||||
for name, type_name, default in cache_configs:
|
||||
if default == list:
|
||||
self.cache[name] = [
|
||||
|
@@ -33,11 +33,15 @@ def from_json(template_type: Any, data: Any) -> Any:
|
||||
instance = None
|
||||
# Handle generics. List[*], Dict[*, *] in particular.
|
||||
elif type(template_type) == typing._GenericAlias: # type: ignore
|
||||
if getattr(template_type, '__origin__') == typing.Union:
|
||||
template_type = template_type.__args__[0]
|
||||
instance = from_json(template_type, data)
|
||||
else:
|
||||
# Having to use this because things changed in Python 3.7.
|
||||
class_name = template_type._name
|
||||
|
||||
# This is not very elegant since it doesn't allow things which sublass
|
||||
# from List or Dict. For my purposes, this doesn't matter.
|
||||
# This is not very elegant since it doesn't allow things which
|
||||
# sublass from List or Dict. For my purposes, this doesn't matter.
|
||||
if class_name == 'List':
|
||||
inner_type = template_type.__args__[0]
|
||||
instance = [from_json(inner_type, value) for value in data]
|
||||
@@ -72,9 +76,13 @@ def from_json(template_type: Any, data: Any) -> Any:
|
||||
# Handle everything else by first instantiating the class, then adding
|
||||
# all of the sub-elements, recursively calling from_json on them.
|
||||
else:
|
||||
instance = template_type()
|
||||
for field, field_type in annotations.items():
|
||||
value = data.get(field)
|
||||
setattr(instance, field, from_json(field_type, value))
|
||||
# for field, field_type in annotations.items():
|
||||
# value = data.get(field)
|
||||
# setattr(instance, field, from_json(field_type, value))
|
||||
instance = template_type(
|
||||
**{
|
||||
field: from_json(field_type, data.get(field))
|
||||
for field, field_type in annotations.items()
|
||||
})
|
||||
|
||||
return instance
|
||||
|
@@ -1,6 +1,8 @@
|
||||
from dataclasses import Field, fields
|
||||
# from dataclasses import Field, fields
|
||||
from typing import Any, Dict
|
||||
|
||||
from sublime.from_json import from_json as _from_json
|
||||
|
||||
|
||||
class APIObject:
|
||||
"""Defines the base class for objects coming from the Subsonic API."""
|
||||
@@ -15,11 +17,4 @@ class APIObject:
|
||||
:param data: a Python dictionary representation of the data to
|
||||
deserialize
|
||||
"""
|
||||
if data is None:
|
||||
return data
|
||||
print('=' * 80)
|
||||
deserialized = cls.__call__(**data)
|
||||
for field in fields(cls):
|
||||
print(field)
|
||||
value = getattr(deserialized, field.name)
|
||||
print('ohea', value)
|
||||
return _from_json(cls, data)
|
||||
|
@@ -8,7 +8,7 @@ script or run it on a new API version.
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import List, Optional
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from sublime.server.api_object import APIObject
|
||||
|
||||
@@ -23,6 +23,9 @@ class AlbumInfo(APIObject):
|
||||
largeImageUrl: List[str] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AverageRating(APIObject, float):
|
||||
@@ -35,6 +38,9 @@ class MediaType(APIObject, Enum):
|
||||
AUDIOBOOK = 'audiobook'
|
||||
VIDEO = 'video'
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UserRating(APIObject, int):
|
||||
@@ -76,12 +82,18 @@ class Child(APIObject):
|
||||
originalWidth: Optional[int] = None
|
||||
originalHeight: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AlbumList(APIObject):
|
||||
album: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AlbumID3(APIObject):
|
||||
@@ -99,12 +111,18 @@ class AlbumID3(APIObject):
|
||||
year: Optional[int] = None
|
||||
genre: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AlbumList2(APIObject):
|
||||
album: List[AlbumID3] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AlbumWithSongsID3(APIObject):
|
||||
@@ -123,6 +141,9 @@ class AlbumWithSongsID3(APIObject):
|
||||
year: Optional[int] = None
|
||||
genre: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Artist(APIObject):
|
||||
@@ -134,6 +155,9 @@ class Artist(APIObject):
|
||||
userRating: Optional[UserRating] = None
|
||||
averageRating: Optional[AverageRating] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArtistInfoBase(APIObject):
|
||||
@@ -145,6 +169,9 @@ class ArtistInfoBase(APIObject):
|
||||
largeImageUrl: List[str] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArtistInfo(APIObject):
|
||||
@@ -157,6 +184,9 @@ class ArtistInfo(APIObject):
|
||||
mediumImageUrl: List[str] = field(default_factory=list)
|
||||
largeImageUrl: List[str] = field(default_factory=list)
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArtistID3(APIObject):
|
||||
@@ -168,6 +198,9 @@ class ArtistID3(APIObject):
|
||||
artistImageUrl: Optional[str] = None
|
||||
starred: Optional[datetime] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArtistInfo2(APIObject):
|
||||
@@ -180,6 +213,9 @@ class ArtistInfo2(APIObject):
|
||||
mediumImageUrl: List[str] = field(default_factory=list)
|
||||
largeImageUrl: List[str] = field(default_factory=list)
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArtistWithAlbumsID3(APIObject):
|
||||
@@ -192,6 +228,9 @@ class ArtistWithAlbumsID3(APIObject):
|
||||
artistImageUrl: Optional[str] = None
|
||||
starred: Optional[datetime] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class IndexID3(APIObject):
|
||||
@@ -199,6 +238,9 @@ class IndexID3(APIObject):
|
||||
artist: List[ArtistID3] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ArtistsID3(APIObject):
|
||||
@@ -206,6 +248,9 @@ class ArtistsID3(APIObject):
|
||||
index: List[IndexID3] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Bookmark(APIObject):
|
||||
@@ -217,12 +262,18 @@ class Bookmark(APIObject):
|
||||
value: Optional[str] = None
|
||||
comment: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Bookmarks(APIObject):
|
||||
bookmark: List[Bookmark] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ChatMessage(APIObject):
|
||||
@@ -231,12 +282,18 @@ class ChatMessage(APIObject):
|
||||
message: str
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ChatMessages(APIObject):
|
||||
chatMessage: List[ChatMessage] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Directory(APIObject):
|
||||
@@ -250,6 +307,9 @@ class Directory(APIObject):
|
||||
averageRating: Optional[AverageRating] = None
|
||||
playCount: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Error(APIObject):
|
||||
@@ -257,6 +317,9 @@ class Error(APIObject):
|
||||
value: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Genre(APIObject):
|
||||
@@ -264,12 +327,18 @@ class Genre(APIObject):
|
||||
albumCount: int
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Genres(APIObject):
|
||||
genre: List[Genre] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Index(APIObject):
|
||||
@@ -277,6 +346,9 @@ class Index(APIObject):
|
||||
artist: List[Artist] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Indexes(APIObject):
|
||||
@@ -287,6 +359,9 @@ class Indexes(APIObject):
|
||||
child: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class InternetRadioStation(APIObject):
|
||||
@@ -296,12 +371,18 @@ class InternetRadioStation(APIObject):
|
||||
value: Optional[str] = None
|
||||
homePageUrl: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class InternetRadioStations(APIObject):
|
||||
internetRadioStation: List[InternetRadioStation] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class JukeboxStatus(APIObject):
|
||||
@@ -311,6 +392,9 @@ class JukeboxStatus(APIObject):
|
||||
value: Optional[str] = None
|
||||
position: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class JukeboxPlaylist(APIObject):
|
||||
@@ -321,6 +405,9 @@ class JukeboxPlaylist(APIObject):
|
||||
value: Optional[str] = None
|
||||
position: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class License(APIObject):
|
||||
@@ -330,6 +417,9 @@ class License(APIObject):
|
||||
licenseExpires: Optional[datetime] = None
|
||||
trialExpires: Optional[datetime] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Lyrics(APIObject):
|
||||
@@ -337,6 +427,9 @@ class Lyrics(APIObject):
|
||||
value: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MusicFolder(APIObject):
|
||||
@@ -344,12 +437,18 @@ class MusicFolder(APIObject):
|
||||
value: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MusicFolders(APIObject):
|
||||
musicFolder: List[MusicFolder] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
class PodcastStatus(APIObject, Enum):
|
||||
NEW = 'new'
|
||||
@@ -359,6 +458,9 @@ class PodcastStatus(APIObject, Enum):
|
||||
DELETED = 'deleted'
|
||||
SKIPPED = 'skipped'
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PodcastEpisode(APIObject):
|
||||
@@ -400,12 +502,18 @@ class PodcastEpisode(APIObject):
|
||||
originalWidth: Optional[int] = None
|
||||
originalHeight: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NewestPodcasts(APIObject):
|
||||
episode: List[PodcastEpisode] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NowPlayingEntry(APIObject):
|
||||
@@ -446,12 +554,18 @@ class NowPlayingEntry(APIObject):
|
||||
originalWidth: Optional[int] = None
|
||||
originalHeight: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class NowPlaying(APIObject):
|
||||
entry: List[NowPlayingEntry] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PlayQueue(APIObject):
|
||||
@@ -463,6 +577,9 @@ class PlayQueue(APIObject):
|
||||
current: Optional[int] = None
|
||||
position: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Playlist(APIObject):
|
||||
@@ -479,6 +596,9 @@ class Playlist(APIObject):
|
||||
public: Optional[bool] = None
|
||||
coverArt: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PlaylistWithSongs(APIObject):
|
||||
@@ -496,12 +616,18 @@ class PlaylistWithSongs(APIObject):
|
||||
public: Optional[bool] = None
|
||||
coverArt: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Playlists(APIObject):
|
||||
playlist: List[Playlist] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PodcastChannel(APIObject):
|
||||
@@ -516,17 +642,26 @@ class PodcastChannel(APIObject):
|
||||
originalImageUrl: Optional[str] = None
|
||||
errorMessage: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Podcasts(APIObject):
|
||||
channel: List[PodcastChannel] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
class ResponseStatus(APIObject, Enum):
|
||||
OK = 'ok'
|
||||
FAILED = 'failed'
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ScanStatus(APIObject):
|
||||
@@ -534,6 +669,9 @@ class ScanStatus(APIObject):
|
||||
value: Optional[str] = None
|
||||
count: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SearchResult(APIObject):
|
||||
@@ -542,6 +680,9 @@ class SearchResult(APIObject):
|
||||
match: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SearchResult2(APIObject):
|
||||
@@ -550,6 +691,9 @@ class SearchResult2(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SearchResult3(APIObject):
|
||||
@@ -558,6 +702,9 @@ class SearchResult3(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Share(APIObject):
|
||||
@@ -572,30 +719,45 @@ class Share(APIObject):
|
||||
expires: Optional[datetime] = None
|
||||
lastVisited: Optional[datetime] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Shares(APIObject):
|
||||
share: List[Share] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SimilarSongs(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SimilarSongs2(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Songs(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Starred(APIObject):
|
||||
@@ -604,6 +766,9 @@ class Starred(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Starred2(APIObject):
|
||||
@@ -612,12 +777,18 @@ class Starred2(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TopSongs(APIObject):
|
||||
song: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class User(APIObject):
|
||||
@@ -641,12 +812,18 @@ class User(APIObject):
|
||||
maxBitRate: Optional[int] = None
|
||||
avatarLastChanged: Optional[datetime] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Users(APIObject):
|
||||
user: List[User] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Version(APIObject, str):
|
||||
@@ -660,6 +837,9 @@ class AudioTrack(APIObject):
|
||||
name: Optional[str] = None
|
||||
languageCode: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Captions(APIObject):
|
||||
@@ -667,6 +847,9 @@ class Captions(APIObject):
|
||||
value: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class VideoConversion(APIObject):
|
||||
@@ -675,6 +858,9 @@ class VideoConversion(APIObject):
|
||||
bitRate: Optional[int] = None
|
||||
audioTrackId: Optional[int] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class VideoInfo(APIObject):
|
||||
@@ -684,12 +870,18 @@ class VideoInfo(APIObject):
|
||||
conversion: List[VideoConversion] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Videos(APIObject):
|
||||
video: List[Child] = field(default_factory=list)
|
||||
value: Optional[str] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Response(APIObject):
|
||||
@@ -739,3 +931,6 @@ class Response(APIObject):
|
||||
value: Optional[str] = None
|
||||
status: Optional[ResponseStatus] = None
|
||||
version: Optional[Version] = None
|
||||
|
||||
def get(self, key: str, default: Any = None) -> Any:
|
||||
return getattr(self, key, default)
|
||||
|
@@ -148,8 +148,7 @@ class Server:
|
||||
)
|
||||
raise Exception(f'Subsonic API Error #{code}: {message}')
|
||||
|
||||
print(subsonic_response)
|
||||
response = Response.from_dict(subsonic_response)
|
||||
response = Response.from_json(subsonic_response)
|
||||
|
||||
# Check for an error and if it exists, raise it.
|
||||
if response.error:
|
||||
|
@@ -66,6 +66,7 @@ class UIState:
|
||||
|
||||
@property
|
||||
def current_song(self) -> Optional[Child]:
|
||||
from sublime.cache_manager import CacheManager
|
||||
if (not self.play_queue or self.current_song_index < 0
|
||||
or not CacheManager.ready()):
|
||||
return None
|
||||
|
@@ -2,10 +2,12 @@ import pytest
|
||||
|
||||
from sublime.adapters import Adapter, AdapterManager
|
||||
|
||||
|
||||
def test_adapter_manager_singleton():
|
||||
AdapterManager.reset()
|
||||
AdapterManager.get_playlists()
|
||||
|
||||
|
||||
def test_functions_not_implemented():
|
||||
with pytest.raises(NotImplementedError):
|
||||
Adapter(None)
|
||||
|
Reference in New Issue
Block a user