diff --git a/yandex_music/__init__.py b/yandex_music/__init__.py index ea716eb..b6c2346 100644 --- a/yandex_music/__init__.py +++ b/yandex_music/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .base import YandexMusicObject from .settings import Settings diff --git a/yandex_music/base.py b/yandex_music/base.py index 7d00dc8..760559b 100644 --- a/yandex_music/base.py +++ b/yandex_music/base.py @@ -1,8 +1,9 @@ from abc import ABCMeta +from typing import Optional import builtins -ujson = False +ujson: bool = False try: import ujson as json ujson = True @@ -14,19 +15,19 @@ reserved_names = [name.lower() for name in dir(builtins)] class YandexMusicObject: __metaclass__ = ABCMeta - _id_attrs = () + _id_attrs: tuple = () - def __str__(self): + def __str__(self) -> str: return str(self.to_dict()) - def __repr__(self): + def __repr__(self) -> str: return str(self) def __getitem__(self, item): return self.__dict__[item] @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client) -> Optional[dict]: if not data: return None @@ -34,10 +35,10 @@ class YandexMusicObject: return data - def to_json(self): + def to_json(self) -> str: return json.dumps(self.to_dict(), ensure_ascii=not ujson) - def to_dict(self): + def to_dict(self) -> dict: def parse(val): if hasattr(val, 'to_dict'): return val.to_dict() @@ -59,7 +60,7 @@ class YandexMusicObject: return parse(data) - def __eq__(self, other): + def __eq__(self, other) -> bool: if isinstance(other, self.__class__): return self._id_attrs == other._id_attrs return super(YandexMusicObject, self).__eq__(other) diff --git a/yandex_music/client.py b/yandex_music/client.py index c718c20..b7ee040 100644 --- a/yandex_music/client.py +++ b/yandex_music/client.py @@ -1,6 +1,7 @@ import logging import functools from datetime import datetime +from typing import Callable, Union, List from yandex_music import YandexMusicObject, Status, Settings, PermissionAlerts, Experiments, Artist, Album, Playlist, \ TracksList, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed, PromoCodeStatus, DownloadInfo, Search, \ @@ -69,7 +70,8 @@ class Client(YandexMusicObject): :class:`yandex_music.utils.request.Request`. """ - def __init__(self, token=None, fetch_account_status=True, base_url=None, oauth_url=None, request=None): + def __init__(self, token: str = None, fetch_account_status: bool = True, base_url: str = None, + oauth_url: str = None, request: Request = None) -> None: self.logger = logging.getLogger(__name__) self.token = token @@ -92,8 +94,8 @@ class Client(YandexMusicObject): self.me = self.account_status() @classmethod - def from_credentials(cls, username, password, x_captcha_answer=None, x_captcha_key=None, captcha_callback=None, - *args, **kwargs): + def from_credentials(cls, username: str, password: str, x_captcha_answer: str = None, x_captcha_key: str = None, + captcha_callback: Callable[[Captcha], str] = None, *args, **kwargs) -> 'Client': """Инициализция клиента по логину и паролю. Note: @@ -132,7 +134,7 @@ class Client(YandexMusicObject): return cls(token, *args, **kwargs) @classmethod - def from_token(cls, token, *args, **kwargs): + def from_token(cls, token: str, *args, **kwargs) -> 'Client': """Инициализция клиента по токену. Ничем не отличается от Client(token). Так исторически сложилось. @@ -148,8 +150,9 @@ class Client(YandexMusicObject): return cls(token, *args, **kwargs) @log - def generate_token_by_username_and_password(self, username, password, grant_type='password', x_captcha_answer=None, - x_captcha_key=None, timeout=None, *args, **kwargs): + def generate_token_by_username_and_password(self, username: str, password: str, grant_type: str = 'password', + x_captcha_answer: str = None, x_captcha_key: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> str: """Метод получения OAuth токена по логину и паролю. Args: @@ -187,7 +190,7 @@ class Client(YandexMusicObject): return result.get('access_token') @staticmethod - def _validate_token(token: str): + def _validate_token(token: str) -> str: """Примитивная валидация токена. Args: @@ -209,12 +212,12 @@ class Client(YandexMusicObject): return token @property - def request(self): + def request(self) -> Request: """:obj:`yandex_music.utils.request.Request`: Объект вспомогательного класса для отправки запросов.""" return self._request @log - def account_status(self, timeout=None, *args, **kwargs): + def account_status(self, timeout: Union[int, float] = None, *args, **kwargs) -> Status: """Получение статуса аккаунта. Нет обязательных параметров. Args: @@ -237,7 +240,7 @@ class Client(YandexMusicObject): return Status.de_json(result, self) @log - def settings(self, timeout=None, *args, **kwargs): + def settings(self, timeout: Union[int, float] = None, *args, **kwargs) -> Settings: """Получение предложений по покупке. Нет обязательных параметров. Args: @@ -260,7 +263,7 @@ class Client(YandexMusicObject): return Settings.de_json(result, self) @log - def permission_alerts(self, timeout=None, *args, **kwargs): + def permission_alerts(self, timeout: Union[int, float] = None, *args, **kwargs) -> PermissionAlerts: """Получение оповещений. Нет обязательных параметров. Args: @@ -283,7 +286,7 @@ class Client(YandexMusicObject): return PermissionAlerts.de_json(result, self) @log - def account_experiments(self, timeout=None, *args, **kwargs): + def account_experiments(self, timeout: Union[int, float] = None, *args, **kwargs) -> Experiments: """Получение значений экспериментальных функций аккаунта. Args: @@ -306,7 +309,8 @@ class Client(YandexMusicObject): return Experiments.de_json(result, self) @log - def consume_promo_code(self, code: str, language: str = 'en', timeout=None, *args, **kwargs): + def consume_promo_code(self, code: str, language: str = 'en', timeout: Union[int, float] = None, + *args, **kwargs) -> PromoCodeStatus: """Активация промо-кода. Args: @@ -331,7 +335,7 @@ class Client(YandexMusicObject): return PromoCodeStatus.de_json(result, self) @log - def feed(self, timeout=None, *args, **kwargs): + def feed(self, timeout: Union[int, float] = None, *args, **kwargs) -> Feed: """Получение потока информации (фида) подобранного под пользователя. Содержит умные плейлисты. Args: @@ -354,7 +358,7 @@ class Client(YandexMusicObject): return Feed.de_json(result, self) @log - def feed_wizard_is_passed(self, timeout=None, *args, **kwargs): + def feed_wizard_is_passed(self, timeout: Union[int, float] = None, *args, **kwargs) -> bool: url = f'{self.base_url}/feed/wizard/is-passed' result = self._request.get(url, timeout=timeout, *args, **kwargs) @@ -362,7 +366,7 @@ class Client(YandexMusicObject): return result.get('is_wizard_passed') or False @log - def landing(self, blocks: str or list, timeout=None, *args, **kwargs): + def landing(self, blocks: Union[str, List[str]], timeout: Union[int, float] = None, *args, **kwargs) -> Landing: """Получение лендинг-страницы содержащий блоки с новыми релизами, чартами, плейлистами с новинками и т.д. Поддерживаемые типы блоков: personalplaylists, promotions, new-releases, new-playlists, mixes,c hart, artists, @@ -389,7 +393,7 @@ class Client(YandexMusicObject): return Landing.de_json(result, self) @log - def genres(self, timeout=None, *args, **kwargs): + def genres(self, timeout: Union[int, float] = None, *args, **kwargs) -> List[Genre]: """Получение жанров музыки. Args: @@ -412,7 +416,8 @@ class Client(YandexMusicObject): return Genre.de_list(result, self) @log - def tracks_download_info(self, track_id: str or int, get_direct_links: bool = False, timeout=None, *args, **kwargs): + def tracks_download_info(self, track_id: Union[str, int], get_direct_links: bool = False, + timeout: Union[int, float] = None, *args, **kwargs) -> List[DownloadInfo]: """Получение информации о доступных вариантах загрузки трека. Args: @@ -437,7 +442,8 @@ class Client(YandexMusicObject): return DownloadInfo.de_list(result, self, get_direct_links) @log - def track_supplement(self, track_id: str or int, timeout=None, *args, **kwargs): + def track_supplement(self, track_id: Union[str, int], timeout: Union[int, float] = None, + *args, **kwargs) -> Supplement: """Получение дополнительной информации о треке. Args: @@ -460,9 +466,9 @@ class Client(YandexMusicObject): @log def play_audio(self, - track_id: str or int, + track_id: Union[str, int], from_: str, - album_id: str or int, + album_id: Union[str, int], playlist_id: str = None, from_cache: bool = False, play_id: str = None, @@ -472,8 +478,8 @@ class Client(YandexMusicObject): total_played_seconds: int = 0, end_position_seconds: int = 0, client_now: str = None, - timeout=None, - *args, **kwargs): + timeout: Union[int, float] = None, + *args, **kwargs) -> bool: """Метод для отправки текущего состояния прослушиваемого трека. Args: @@ -524,7 +530,8 @@ class Client(YandexMusicObject): return result == 'ok' - def albums_with_tracks(self, album_id: str or int, timeout=None, *args, **kwargs): + def albums_with_tracks(self, album_id: Union[str, int], timeout: Union[int, float] = None, + *args, **kwargs) -> Album: """Получение альбома по его уникальному идентификатору вместе с треками. Args: @@ -554,8 +561,8 @@ class Client(YandexMusicObject): type_: str = 'all', page: int = 0, playlist_in_best: bool = True, - timeout=None, - *args, **kwargs): + timeout: Union[int, float] = None, + *args, **kwargs) -> Search: """Осуществление поиска по запросу и типу, получение результатов. Args: @@ -591,7 +598,7 @@ class Client(YandexMusicObject): return Search.de_json(result, self) @log - def search_suggest(self, part: str, timeout=None, *args, **kwargs): + def search_suggest(self, part: str, timeout: Union[int, float] = None, *args, **kwargs) -> Suggestions: """Получение подсказок по введенной части поискового запроса. Args: @@ -615,7 +622,8 @@ class Client(YandexMusicObject): return Suggestions.de_json(result, self) @log - def users_playlists(self, kind: str or int or list, user_id: str = None, timeout=None, *args, **kwargs): + def users_playlists(self, kind: Union[List[Union[str, int]], str, int], user_id: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> List[Playlist]: """Получение плейлиста или списка плейлистов по уникальным идентификаторам. Args: @@ -649,7 +657,7 @@ class Client(YandexMusicObject): @log def users_playlists_create(self, title: str, visibility: str = 'public', user_id: str = None, - timeout=None, *args, **kwargs): + timeout: Union[int, float] = None, *args, **kwargs) -> Playlist: """Создание плейлиста. Args: @@ -683,8 +691,8 @@ class Client(YandexMusicObject): return Playlist.de_json(result, self) @log - def users_playlists_delete(self, kind: str or int, user_id: str = None, - timeout=None, *args, **kwargs): + def users_playlists_delete(self, kind: Union[str, int], user_id: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: """Удаление плейлиста. Args: @@ -711,7 +719,8 @@ class Client(YandexMusicObject): return result == 'ok' @log - def users_playlists_name(self, kind: str or int, name: str, user_id: str = None, timeout=None, *args, **kwargs): + def users_playlists_name(self, kind: Union[str, int], name: str, user_id: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> Playlist: """Изменение названия плейлиста. Args: @@ -740,8 +749,8 @@ class Client(YandexMusicObject): return Playlist.de_json(result, self) @log - def users_playlists_change(self, kind: str or int, diff: str, revision: int = 1, user_id: str = None, - timeout=None, *args, **kwargs): + def users_playlists_change(self, kind: Union[str, int], diff: str, revision: int = 1, user_id: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> Playlist: """Изменение плейлиста. Для получения отличий есть вспомогательный класс :class:`from yandex_music.utils.difference.Difference`. @@ -780,8 +789,9 @@ class Client(YandexMusicObject): return Playlist.de_json(result, self) @log - def users_playlists_insert_track(self, kind: str or int, track_id: str or int, album_id: str or int, at: int = 0, - revision: int = 1, user_id: str = None, timeout=None, *args, **kwargs): + def users_playlists_insert_track(self, kind: Union[str, int], track_id: Union[str, int], album_id: Union[str, int], + at: int = 0, revision: int = 1, user_id: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> Playlist: """Добавление трека в плейлист. Трек можно вставить с любое место плейлиста задав индекс вставки (аргумент at). @@ -813,8 +823,9 @@ class Client(YandexMusicObject): return self.users_playlists_change(kind, diff.to_json(), revision, user_id, timeout, *args, **kwargs) @log - def users_playlists_delete_track(self, kind: str or int, from_: int, to: int, revision: int = 1, - user_id: str = None, timeout=None, *args, **kwargs): + def users_playlists_delete_track(self, kind: Union[str, int], from_: int, to: int, revision: int = 1, + user_id: str = None, timeout: Union[int, float] = None, + *args, **kwargs) -> Playlist: """Удаление треков из плейлиста. Для удаление необходимо указать границы с какого по какой элемент (трек) удалить. @@ -845,7 +856,7 @@ class Client(YandexMusicObject): return self.users_playlists_change(kind, diff.to_json(), revision, user_id, timeout, *args, **kwargs) @log - def rotor_account_status(self, timeout=None, *args, **kwargs): + def rotor_account_status(self, timeout: Union[int, float] = None, *args, **kwargs) -> Status: url = f'{self.base_url}/rotor/account/status' result = self._request.get(url, timeout=timeout, *args, **kwargs) @@ -853,7 +864,7 @@ class Client(YandexMusicObject): return Status.de_json(result, self) @log - def rotor_stations_dashboard(self, timeout=None, *args, **kwargs): + def rotor_stations_dashboard(self, timeout: Union[int, float] = None, *args, **kwargs) -> Dashboard: url = f'{self.base_url}/rotor/stations/dashboard' result = self._request.get(url, timeout=timeout, *args, **kwargs) @@ -861,7 +872,8 @@ class Client(YandexMusicObject): return Dashboard.de_json(result, self) @log - def rotor_stations_list(self, language: str = 'en', timeout=None, *args, **kwargs): + def rotor_stations_list(self, language: str = 'en', timeout: Union[int, float] = None, + *args, **kwargs) -> List[StationResult]: url = f'{self.base_url}/rotor/stations/list' result = self._request.get(url, {'language': language}, timeout=timeout, *args, **kwargs) @@ -869,8 +881,9 @@ class Client(YandexMusicObject): return StationResult.de_list(result, self) @log - def rotor_station_genre_feedback(self, genre: str, type_: str, timestamp=None, from_: str = None, - batch_id: str or int = None, track_id: str = None, timeout=None, *args, **kwargs): + def rotor_station_genre_feedback(self, genre: str, type_: str, timestamp: int = None, from_: str = None, + batch_id: Union[str, int] = None, track_id: str = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: if timestamp is None: timestamp = datetime.now().timestamp() @@ -894,18 +907,20 @@ class Client(YandexMusicObject): return result == 'ok' @log - def rotor_station_genre_feedback_radio_started(self, genre: str, from_: str, timestamp=None, - timeout=None, *args, **kwargs): + def rotor_station_genre_feedback_radio_started(self, genre: str, from_: str, timestamp: int = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self.rotor_station_genre_feedback(genre, 'radioStarted', timestamp, from_, timeout, *args, **kwargs) @log - def rotor_station_genre_feedback_track_started(self, genre: str, track_id: str, batch_id: str or int, - timestamp=None, timeout=None, *args, **kwargs): + def rotor_station_genre_feedback_track_started(self, genre: str, track_id: str, batch_id: Union[str, int], + timestamp: int = None, timeout: Union[int, float] = None, + *args, **kwargs) -> bool: return self.rotor_station_genre_feedback(genre, 'trackStarted', timestamp, track_id=track_id, batch_id=batch_id, timeout=timeout, *args, **kwargs) @log - def rotor_station_genre_info(self, genre: str, timeout=None, *args, **kwargs): + def rotor_station_genre_info(self, genre: str, timeout: Union[int, float] = None, + *args, **kwargs) -> List[StationResult]: url = f'{self.base_url}/rotor/station/genre:{genre}/info' result = self._request.get(url, timeout=timeout, *args, **kwargs) @@ -913,7 +928,8 @@ class Client(YandexMusicObject): return StationResult.de_list(result, self) @log - def rotor_station_genre_tracks(self, genre: str, timeout=None, *args, **kwargs): + def rotor_station_genre_tracks(self, genre: str, timeout: Union[int, float] = None, + *args, **kwargs) -> StationTracksResult: url = f'{self.base_url}/rotor/station/genre:{genre}/tracks' result = self._request.get(url, timeout=timeout, *args, **kwargs) @@ -921,7 +937,8 @@ class Client(YandexMusicObject): return StationTracksResult.de_json(result, self) @log - def artists_brief_info(self, artist_id: str or int, timeout=None, *args, **kwargs): + def artists_brief_info(self, artist_id: Union[str, int], timeout: Union[int, float] = None, + *args, **kwargs) -> BriefInfo: url = f'{self.base_url}/artists/{artist_id}/brief-info' result = self._request.get(url, timeout=timeout, *args, **kwargs) @@ -929,7 +946,8 @@ class Client(YandexMusicObject): return BriefInfo.de_json(result, self) @log - def artists_tracks(self, artist_id: str or int, page=0, page_size=20, timeout=None, *args, **kwargs): + def artists_tracks(self, artist_id: Union[str, int], page: int = 0, page_size: int = 20, + timeout: Union[int, float] = None, *args, **kwargs) -> ArtistTracks: """Получение треков артиста. Args: @@ -960,8 +978,9 @@ class Client(YandexMusicObject): return ArtistTracks.de_json(result, self) @log - def artists_direct_albums(self, artist_id: str or int, page=0, page_size=20, sort_by='year', - timeout=None, *args, **kwargs): + def artists_direct_albums(self, artist_id: Union[str, int], page: int = 0, page_size: int = 20, + sort_by: str = 'year', timeout: Union[int, float] = None, + *args, **kwargs) -> ArtistAlbums: """Получение альбомов артиста. Известные значения для sort_by: year, rating. @@ -995,8 +1014,8 @@ class Client(YandexMusicObject): return ArtistAlbums.de_json(result, self) - def _like_action(self, object_type: str, ids: str or int or list, remove: bool = False, user_id: str or int = None, - timeout=None, *args, **kwargs): + def _like_action(self, object_type: str, ids: Union[List[Union[str, int]], str, int], remove: bool = False, + user_id: Union[str, int] = None, timeout: Union[int, float] = None, *args, **kwargs) -> bool: if user_id is None and self.me is not None: user_id = self.me.account.uid @@ -1011,45 +1030,53 @@ class Client(YandexMusicObject): return result == 'ok' @log - def users_likes_tracks_add(self, track_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_tracks_add(self, track_ids: Union[List[Union[str, int]], str, int], user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('track', track_ids, False, user_id, timeout, *args, **kwargs) @log - def users_likes_tracks_remove(self, track_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_tracks_remove(self, track_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('track', track_ids, True, user_id, timeout, *args, **kwargs) @log - def users_likes_artists_add(self, artist_ids: str or int or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_artists_add(self, artist_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('artist', artist_ids, False, user_id, timeout, *args, **kwargs) - def users_likes_artists_remove(self, artist_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_artists_remove(self, artist_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('artist', artist_ids, True, user_id, timeout, *args, **kwargs) @log - def users_likes_playlists_add(self, playlist_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_playlists_add(self, playlist_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('playlist', playlist_ids, False, user_id, timeout, *args, **kwargs) @log - def users_likes_playlists_remove(self, playlist_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_playlists_remove(self, playlist_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('playlist', playlist_ids, True, user_id, timeout, *args, **kwargs) @log - def users_likes_albums_add(self, album_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_albums_add(self, album_ids: Union[List[Union[str, int]], str, int], user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('album', album_ids, False, user_id, timeout, *args, **kwargs) @log - def users_likes_albums_remove(self, album_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_likes_albums_remove(self, album_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._like_action('album', album_ids, True, user_id, timeout, *args, **kwargs) - def _get_list(self, object_type: str, ids: list or int or str, params=None, timeout=None, *args, **kwargs): + def _get_list(self, object_type: str, ids: Union[List[Union[str, int]], int, str], + params: dict = None, timeout: Union[int, float] = None, + *args, **kwargs) -> List[Union[Artist, Album, Track, Playlist]]: if params is None: params = {} params.update({f'{object_type}-ids': ids}) @@ -1061,23 +1088,28 @@ class Client(YandexMusicObject): return de_list.get(object_type)(result, self) @log - def artists(self, artist_ids: list or int or str, timeout=None, *args, **kwargs): - return self._get_list('artist', artist_ids, timeout, *args, **kwargs) + def artists(self, artist_ids: Union[List[Union[str, int]], int, str], timeout: Union[int, float] = None, + *args, **kwargs) -> List[Artist]: + return self._get_list('artist', artist_ids, timeout=timeout, *args, **kwargs) @log - def albums(self, album_ids: list or int or str, timeout=None, *args, **kwargs): - return self._get_list('album', album_ids, timeout, *args, **kwargs) + def albums(self, album_ids: Union[List[Union[str, int]], int, str], timeout: Union[int, float] = None, + *args, **kwargs) -> List[Album]: + return self._get_list('album', album_ids, timeout=timeout, *args, **kwargs) @log - def tracks(self, track_ids: int or str, with_positions=True, timeout=None, *args, **kwargs): + def tracks(self, track_ids: Union[List[Union[str, int]], int, str], with_positions: bool = True, + timeout: Union[int, float] = None, *args, **kwargs) -> List[Track]: return self._get_list('track', track_ids, {'with-positions': with_positions}, timeout, *args, **kwargs) @log - def playlists_list(self, playlist_ids: list or int or str, timeout=None, *args, **kwargs): - return self._get_list('playlist', playlist_ids, timeout, *args, **kwargs) + def playlists_list(self, playlist_ids: Union[List[Union[str, int]], int, str], timeout: Union[int, float] = None, + *args, **kwargs) -> List[Playlist]: + return self._get_list('playlist', playlist_ids, timeout=timeout, *args, **kwargs) @log - def users_playlists_list(self, user_id: int or str = None, timeout=None, *args, **kwargs): + def users_playlists_list(self, user_id: Union[str, int] = None, timeout: Union[int, float] = None, + *args, **kwargs) -> List[Playlist]: if user_id is None and self.me is not None: user_id = self.me.account.uid @@ -1087,7 +1119,9 @@ class Client(YandexMusicObject): return Playlist.de_list(result, self) - def _get_likes(self, object_type, user_id: int or str = None, params=None, timeout=None, *args, **kwargs): + def _get_likes(self, object_type: str, user_id: Union[str, int] = None, params: dict = None, + timeout: Union[int, float] = None, *args, **kwargs) \ + -> Union[List[ArtistsLikes], List[AlbumsLikes], List[PlaylistsLikes], TracksList]: if user_id is None and self.me is not None: user_id = self.me.account.uid @@ -1101,26 +1135,29 @@ class Client(YandexMusicObject): return de_list_likes.get(object_type)(result, self) @log - def users_likes_tracks(self, user_id: int or str = None, if_modified_since_revision=0, timeout=None, - *args, **kwargs): + def users_likes_tracks(self, user_id: Union[str, int] = None, if_modified_since_revision: int = 0, + timeout: Union[int, float] = None, *args, **kwargs) -> TracksList: return self._get_likes('track', user_id, {'if-modified-since-revision': if_modified_since_revision}, timeout, *args, **kwargs) @log - def users_likes_albums(self, user_id: int or str = None, rich=True, timeout=None, *args, **kwargs): + def users_likes_albums(self, user_id: Union[str, int] = None, rich: bool = True, timeout: Union[int, float] = None, + *args, **kwargs) -> List[AlbumsLikes]: return self._get_likes('album', user_id, {'rich': rich}, timeout, *args, **kwargs) @log - def users_likes_artists(self, user_id: int or str = None, with_timestamps=True, timeout=None, *args, **kwargs): + def users_likes_artists(self, user_id: Union[str, int] = None, with_timestamps: bool = True, + timeout: Union[int, float] = None, *args, **kwargs) -> List[ArtistsLikes]: return self._get_likes('artist', user_id, {'with-timestamps': with_timestamps}, timeout, *args, **kwargs) @log - def users_likes_playlists(self, user_id: int or str = None, timeout=None, *args, **kwargs): + def users_likes_playlists(self, user_id: Union[str, int] = None, timeout: Union[int, float] = None, + *args, **kwargs) -> List[PlaylistsLikes]: return self._get_likes('playlist', user_id, timeout=timeout, *args, **kwargs) @log - def users_dislikes_tracks(self, user_id: int or str = None, if_modified_since_revision=0, - timeout=None, *args, **kwargs): + def users_dislikes_tracks(self, user_id: Union[str, int] = None, if_modified_since_revision: int = 0, + timeout: Union[int, float] = None, *args, **kwargs) -> TracksList: if user_id is None and self.me is not None: user_id = self.me.account.uid @@ -1131,8 +1168,8 @@ class Client(YandexMusicObject): return TracksList.de_json(result.get('library'), self) - def _dislike_action(self, ids: str or int or list, remove: bool = False, user_id: str or int = None, - timeout=None, *args, **kwargs): + def _dislike_action(self, ids: Union[List[Union[str, int]], str, int], remove: bool = False, + user_id: Union[str, int] = None, timeout: Union[int, float] = None, *args, **kwargs) -> bool: if user_id is None and self.me is not None: user_id = self.me.account.uid @@ -1144,13 +1181,15 @@ class Client(YandexMusicObject): return 'revision' in result @log - def users_dislikes_tracks_add(self, track_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_dislikes_tracks_add(self, track_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._dislike_action(track_ids, False, user_id, timeout, *args, **kwargs) @log - def users_dislikes_tracks_remove(self, track_ids: str or list, user_id: str or int = None, - timeout=None, *args, **kwargs): + def users_dislikes_tracks_remove(self, track_ids: Union[List[Union[str, int]], str, int], + user_id: Union[str, int] = None, + timeout: Union[int, float] = None, *args, **kwargs) -> bool: return self._dislike_action(track_ids, True, user_id, timeout, *args, **kwargs) # camelCase псевдонимы diff --git a/yandex_music/cover.py b/yandex_music/cover.py index c0da12a..39a40f9 100644 --- a/yandex_music/cover.py +++ b/yandex_music/cover.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional, List + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -31,15 +36,15 @@ class Cover(YandexMusicObject): """ def __init__(self, - type_=None, - uri=None, - items_uri=None, - dir_=None, - version=None, - custom=None, - prefix=None, - error=None, - client=None, + type_: Optional[str] = None, + uri: Optional[str] = None, + items_uri: Optional[str] = None, + dir_: Optional[str] = None, + version: Optional[str] = None, + custom: Optional[bool] = None, + prefix: Optional[str] = None, + error: Optional[str] = None, + client: Optional['Client'] = None, **kwargs): self.type = type_ self.uri = uri @@ -53,7 +58,7 @@ class Cover(YandexMusicObject): self.client = client self._id_attrs = (self.prefix, self.version, self.uri, self.items_uri) - def download(self, filename, index=0, size='200x200'): + def download(self, filename: str, index: int = 0, size: str = '200x200') -> None: """Загрузка обложки. Args: @@ -67,7 +72,7 @@ class Cover(YandexMusicObject): self.client.request.download(f'https://{uri.replace("%%", size)}', filename) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['Cover']: """Десериализация объекта. Args: @@ -86,7 +91,7 @@ class Cover(YandexMusicObject): return cls(client=client, **data) @classmethod - def de_list(cls, data, client): + def de_list(cls, data: dict, client: 'Client') -> List['Cover']: """Десериализация списка объектов. Args: diff --git a/yandex_music/download_info.py b/yandex_music/download_info.py index 192ffd9..6f4d352 100644 --- a/yandex_music/download_info.py +++ b/yandex_music/download_info.py @@ -1,3 +1,9 @@ +from typing import TYPE_CHECKING, Optional, List + +if TYPE_CHECKING: + from yandex_music import Client + from xml.dom.minicompat import NodeList + from hashlib import md5 import xml.dom.minidom as minidom @@ -29,12 +35,12 @@ class DownloadInfo(YandexMusicObject): """ def __init__(self, - codec, - bitrate_in_kbps, - gain, - preview, - download_info_url, - client=None, + codec: str, + bitrate_in_kbps: int, + gain: bool, + preview: bool, + download_info_url: str, + client: Optional['Client'] = None, **kwargs): self.codec = codec self.bitrate_in_kbps = bitrate_in_kbps @@ -48,7 +54,7 @@ class DownloadInfo(YandexMusicObject): self._id_attrs = (self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url) @staticmethod - def _get_text_node_data(elements): + def _get_text_node_data(elements: 'NodeList') -> str: """:obj:`str`: Получение текстовой информации из узлов XML элемента.""" for element in elements: nodes = element.childNodes @@ -56,7 +62,7 @@ class DownloadInfo(YandexMusicObject): if node.nodeType == node.TEXT_NODE: return node.data - def get_direct_link(self): + def get_direct_link(self) -> str: """Получение прямой ссылки на загрузку из XML ответа. Метод доступен только одну минуту с момента получения информации о загрузке, иначе 410 ошибка! @@ -80,7 +86,7 @@ class DownloadInfo(YandexMusicObject): return self.direct_link - def download(self, filename): + def download(self, filename: str) -> None: """Загрузка трека. Args: @@ -93,7 +99,7 @@ class DownloadInfo(YandexMusicObject): self.client.request.download(self.direct_link, filename) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['DownloadInfo']: """Десериализация объекта. Args: @@ -112,7 +118,7 @@ class DownloadInfo(YandexMusicObject): return cls(client=client, **data) @classmethod - def de_list(cls, data, client, get_direct_links=False): + def de_list(cls, data: dict, client: 'Client', get_direct_links: bool = False) -> List['DownloadInfo']: """Десериализация списка объектов. Args: diff --git a/yandex_music/exceptions.py b/yandex_music/exceptions.py index 6eb0949..df0ae76 100644 --- a/yandex_music/exceptions.py +++ b/yandex_music/exceptions.py @@ -1,3 +1,9 @@ +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from yandex_music.utils.captcha_response import CaptchaResponse + + class YandexMusicError(Exception): """Базовый класс, представляющий исключения общего характера. """ @@ -33,7 +39,7 @@ class Captcha(YandexMusicError): :class:`yandex_music.utils.captcha_response.CaptchaResponse` представляющий капчу. """ - def __init__(self, msg, captcha, *args, **kwargs): + def __init__(self, msg: str, captcha: 'CaptchaResponse', *args, **kwargs): self.captcha = captcha super().__init__(msg, *args, **kwargs) diff --git a/yandex_music/experiments.py b/yandex_music/experiments.py index b0cac56..3928217 100644 --- a/yandex_music/experiments.py +++ b/yandex_music/experiments.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -16,14 +21,14 @@ class Experiments(YandexMusicObject): """ def __init__(self, - client=None, + client: Optional['Client'] = None, **kwargs): self.__dict__.update(kwargs) self.client = client @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['Experiments']: """Десериализация объекта. Args: diff --git a/yandex_music/icon.py b/yandex_music/icon.py index fa4f14b..0bd47ac 100644 --- a/yandex_music/icon.py +++ b/yandex_music/icon.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -19,9 +24,9 @@ class Icon(YandexMusicObject): """ def __init__(self, - background_color, - image_url, - client=None, + background_color: str, + image_url: str, + client: Optional['Client'] = None, **kwargs): self.background_color = background_color self.image_url = image_url @@ -29,7 +34,7 @@ class Icon(YandexMusicObject): self.client = client self._id_attrs = (self.background_color, self.image_url) - def download(self, filename, size='200x200'): + def download(self, filename: str, size: str = '200x200'): """Загрузка иконки. Args: @@ -40,7 +45,7 @@ class Icon(YandexMusicObject): self.client.request.download(f'https://{self.image_url.replace("%%", size)}', filename) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['Icon']: """Десериализация объекта. Args: diff --git a/yandex_music/invocation_info.py b/yandex_music/invocation_info.py index 10deee1..bb29d70 100644 --- a/yandex_music/invocation_info.py +++ b/yandex_music/invocation_info.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -21,10 +26,10 @@ class InvocationInfo(YandexMusicObject): """ def __init__(self, - hostname, - req_id, - exec_duration_millis=None, - client=None, + hostname: str, + req_id: str, + exec_duration_millis: Optional[str] = None, + client: Optional['Client'] = None, **kwargs): self.hostname = hostname self.req_id = req_id @@ -35,7 +40,7 @@ class InvocationInfo(YandexMusicObject): self._id_attrs = (self.hostname, self.req_id) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['InvocationInfo']: """Десериализация объекта. Args: diff --git a/yandex_music/pager.py b/yandex_music/pager.py index bf15c47..5e24cd7 100644 --- a/yandex_music/pager.py +++ b/yandex_music/pager.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -21,10 +26,10 @@ class Pager(YandexMusicObject): """ def __init__(self, - total, - page, - per_page, - client=None, + total: int, + page: int, + per_page: int, + client: Optional['Client'] = None, **kwargs): self.total = total self.page = page @@ -34,7 +39,7 @@ class Pager(YandexMusicObject): self._id_attrs = (self.total, self.page, self.per_page) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['Pager']: """Десериализация объекта. Args: diff --git a/yandex_music/permission_alerts.py b/yandex_music/permission_alerts.py index e605b90..28dbd96 100644 --- a/yandex_music/permission_alerts.py +++ b/yandex_music/permission_alerts.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -18,14 +23,14 @@ class PermissionAlerts(YandexMusicObject): def __init__(self, alerts, - client=None, + client: Optional['Client'] = None, **kwargs): self.alerts = alerts self.client = client @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['PermissionAlerts']: """Десериализация объекта. Args: diff --git a/yandex_music/promo_code_status.py b/yandex_music/promo_code_status.py index 34c7a4e..8c31a09 100644 --- a/yandex_music/promo_code_status.py +++ b/yandex_music/promo_code_status.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from yandex_music import Client, Status + from yandex_music import YandexMusicObject @@ -23,10 +28,10 @@ class PromoCodeStatus(YandexMusicObject): """ def __init__(self, - status, - status_desc, - account_status, - client=None, + status: str, + status_desc: str, + account_status: 'Status', + client: Optional['Client'] = None, **kwargs): self.status = status self.status_desc = status_desc @@ -36,7 +41,7 @@ class PromoCodeStatus(YandexMusicObject): self._id_attrs = (self.status, self.status_desc, self.account_status) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['PromoCodeStatus']: """Десериализация объекта. Args: diff --git a/yandex_music/settings.py b/yandex_music/settings.py index a328768..adb95af 100644 --- a/yandex_music/settings.py +++ b/yandex_music/settings.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional, List + +if TYPE_CHECKING: + from yandex_music import Client, Product, Price + from yandex_music import YandexMusicObject @@ -7,7 +12,7 @@ class Settings(YandexMusicObject): Attributes: in_app_products (:obj:`list` из :obj:`yandex_music.Product`): Список объектов класса :class:`yandex_music.Product` представляющий продаваемые продукты внутри приложения. - native_products (:obj:`list`) из :obj:`yandex_music.Product`: Список объектов класса + native_products (:obj:`list` из :obj:`yandex_music.Product`): Список объектов класса :class:`yandex_music.Product` представляющий продаваемые продукты всплывающими окнами. web_payment_url (:obj:`str`): Ссылка для осуществления платежа. web_payment_month_product_price (:obj:`yandex_music.Price`): Объект класса :class:`yandex_music.Price` @@ -31,12 +36,12 @@ class Settings(YandexMusicObject): """ def __init__(self, - in_app_products, - native_products, - web_payment_url, - promo_codes_enabled, - web_payment_month_product_price=None, - client=None, + in_app_products: List['Product'], + native_products: List['Product'], + web_payment_url: str, + promo_codes_enabled: bool, + web_payment_month_product_price: Optional['Price'] = None, + client: Optional['Client'] = None, **kwargs): self.in_app_products = in_app_products self.native_products = native_products @@ -48,7 +53,7 @@ class Settings(YandexMusicObject): self._id_attrs = (self.in_app_products, self.native_products, self.web_payment_url, self.promo_codes_enabled) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['Settings']: """Десериализация объекта. Args: diff --git a/yandex_music/track_short.py b/yandex_music/track_short.py index 187bdfc..987f714 100644 --- a/yandex_music/track_short.py +++ b/yandex_music/track_short.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional, List + +if TYPE_CHECKING: + from yandex_music import Client, Track + from yandex_music import YandexMusicObject @@ -21,10 +26,10 @@ class TrackShort(YandexMusicObject): """ def __init__(self, - id_, - timestamp, - album_id=None, - client=None, + id_: str, + timestamp: str, + album_id: Optional[str] = None, + client: Optional['Client'] = None, **kwargs): self.id = id_ self.timestamp = timestamp @@ -37,7 +42,7 @@ class TrackShort(YandexMusicObject): self._id_attrs = (self.id, self.album_id) @property - def track(self): + def track(self) -> 'Track': """:obj:`yandex_music.Track`: Объект класса :class:`yandex_music.Track` представляющий полную версию трека.""" if self._track: return self._track @@ -47,7 +52,7 @@ class TrackShort(YandexMusicObject): return self._track @property - def track_id(self): + def track_id(self) -> str: """:obj:`str`: Уникальный идентификатор трека состоящий из его номера и номера альбома или просто из номера.""" if self.album_id: @@ -56,7 +61,7 @@ class TrackShort(YandexMusicObject): return f'{self.id}' @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['TrackShort']: """Десериализация объекта. Args: @@ -75,7 +80,7 @@ class TrackShort(YandexMusicObject): return cls(client=client, **data) @classmethod - def de_list(cls, data, client): + def de_list(cls, data: dict, client: 'Client') -> List['TrackShort']: """Десериализация списка объектов. Args: diff --git a/yandex_music/tracks_list.py b/yandex_music/tracks_list.py index 63b61cc..668c1b3 100644 --- a/yandex_music/tracks_list.py +++ b/yandex_music/tracks_list.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional, List, Iterator + +if TYPE_CHECKING: + from yandex_music import Client, TrackShort + from yandex_music import YandexMusicObject @@ -21,10 +26,10 @@ class TracksList(YandexMusicObject): """ def __init__(self, - uid, - revision, - tracks, - client=None, + uid: int, + revision: int, + tracks: List['TrackShort'], + client: Optional['Client'] = None, **kwargs): self.uid = uid self.revision = revision @@ -33,19 +38,19 @@ class TracksList(YandexMusicObject): self.client = client self._id_attrs = (self.uid, self.tracks) - def __getitem__(self, item): + def __getitem__(self, item) -> 'TrackShort': return self.tracks[item] - def __iter__(self): + def __iter__(self) -> Iterator['TrackShort']: return iter(self.tracks) @property - def tracks_ids(self): + def tracks_ids(self) -> List[str]: """:obj:`list` из :obj:`str`: Список уникальных идентификаторов треков.""" return [track.track_id for track in self.tracks] @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['TracksList']: """Десериализация объекта. Args: diff --git a/yandex_music/video.py b/yandex_music/video.py index f666645..60de6ac 100644 --- a/yandex_music/video.py +++ b/yandex_music/video.py @@ -1,3 +1,8 @@ +from typing import TYPE_CHECKING, Optional, List + +if TYPE_CHECKING: + from yandex_music import Client + from yandex_music import YandexMusicObject @@ -14,7 +19,7 @@ class Video(YandexMusicObject): text=None, html_auto_play_video_player=None, regions=None, - client=None, + client: Optional['Client'] = None, **kwargs): self.title = title @@ -36,7 +41,7 @@ class Video(YandexMusicObject): self._id_attrs = (self.provider_video_id, self.youtube_url, self.title) @classmethod - def de_json(cls, data, client): + def de_json(cls, data: dict, client: 'Client') -> Optional['Video']: if not data: return None @@ -45,7 +50,7 @@ class Video(YandexMusicObject): return cls(client=client, **data) @classmethod - def de_list(cls, data, client): + def de_list(cls, data: dict, client: 'Client') -> List['Video']: if not data: return []