From 16aae08b075d5731c75d2bac3bac099e65dcc3a0 Mon Sep 17 00:00:00 2001 From: Il`ya Date: Sat, 25 Jan 2020 19:46:25 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20TracksSimilar=20?= =?UTF-8?q?=D1=81=20=D0=BF=D0=BE=D0=BB=D1=8F=D0=BC=D0=B8=20=D1=82=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D0=B0=20=D0=B8=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=BE=D1=85=D0=BE=D0=B6=D0=B8=D1=85=20=D1=82?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D0=BE=D0=B2.=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D0=BF=D0=BE=D1=85=D0=BE=D0=B6=D0=B8=D1=85=20?= =?UTF-8?q?=D1=82=D1=80=D0=B5=D0=BA=D0=BE=D0=B2.=20#197?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yandex_music/__init__.py | 3 ++- yandex_music/client.py | 11 +++++++++- yandex_music/track/tracks_similar.py | 31 ++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 yandex_music/track/tracks_similar.py diff --git a/yandex_music/__init__.py b/yandex_music/__init__.py index f5d2c01..c70a79c 100644 --- a/yandex_music/__init__.py +++ b/yandex_music/__init__.py @@ -44,6 +44,7 @@ from .tracks_list import TracksList from .track.major import Major from .track.normalization import Normalization from .track.track import Track +from .track.tracks_similar import TracksSimilar from .likes.albums_likes import AlbumsLikes from .likes.artists_likes import ArtistsLikes @@ -119,4 +120,4 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio 'Icon', 'Images', 'Id', 'Station', 'Dashboard', 'RotorSettings', 'AdParams', 'Restrictions', 'Value', 'Enum', 'DiscreteScale', 'StationResult', 'Sequence', 'StationTracksResult', 'BriefInfo', 'Description', 'PlaylistId', 'Vinyl', 'Supplement', 'Lyrics', 'VideoSupplement', 'ArtistTracks', 'Pager', 'ArtistAlbums', - 'PlaylistAbsence', 'Shot', 'ShotEvent', 'ShotType', 'ShotData'] + 'PlaylistAbsence', 'Shot', 'ShotEvent', 'ShotType', 'ShotData', 'TracksSimilar'] diff --git a/yandex_music/client.py b/yandex_music/client.py index 795c4d7..45a445e 100644 --- a/yandex_music/client.py +++ b/yandex_music/client.py @@ -6,7 +6,7 @@ from typing import Callable, Union, List, Optional from yandex_music import YandexMusicObject, Status, Settings, PermissionAlerts, Experiments, Artist, Album, Playlist, \ TracksList, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed, PromoCodeStatus, DownloadInfo, Search, \ Suggestions, Landing, Genre, Dashboard, StationResult, StationTracksResult, BriefInfo, Supplement, ArtistTracks, \ - ArtistAlbums, ShotEvent + ArtistAlbums, ShotEvent, TracksSimilar from yandex_music.utils.request import Request from yandex_music.utils.difference import Difference from yandex_music.exceptions import InvalidToken, Captcha @@ -465,6 +465,15 @@ class Client(YandexMusicObject): return Supplement.de_json(result, self) + @log + def tracks_similar(self, track_id: Union[str, int], timeout: Union[int, float] = None, + *args, **kwargs) -> Optional: + url = f'{self.base_url}/tracks/{track_id}/similar' + + result = self._request.get(url, timeout=timeout, *args, **kwargs) + + return TracksSimilar.de_json(result, self) + @log def play_audio(self, track_id: Union[str, int], diff --git a/yandex_music/track/tracks_similar.py b/yandex_music/track/tracks_similar.py new file mode 100644 index 0000000..c9e3e73 --- /dev/null +++ b/yandex_music/track/tracks_similar.py @@ -0,0 +1,31 @@ +from typing import TYPE_CHECKING, Optional, List + +if TYPE_CHECKING: + from yandex_music import Client, Track + +from yandex_music import YandexMusicObject + + +class TracksSimilar(YandexMusicObject): + def __init__(self, + track: Optional['Track'], + similar_tracks: List['Track'], + client: Optional['Client'] = None, + **kwargs) -> None: + self.track = track + self.similar_tracks = similar_tracks + + self.client = client + self._id_attrs = (self.track, self.similar_tracks) + + @classmethod + def de_json(cls, data: dict, client: 'Client') -> Optional['TracksSimilar']: + if not data: + return None + + data = super(TracksSimilar, cls).de_json(data, client) + from yandex_music import Track + data['track'] = Track.de_json(data.get('track'), client) + data['similar_tracks'] = Track.de_list(data.get('similar_tracks'), client) + + return cls(client=client, **data) From 4188bc829290d5bd085cd2a329d2d36572ce386f Mon Sep 17 00:00:00 2001 From: Il`ya Date: Sat, 25 Jan 2020 19:55:44 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8F.=20#197?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yandex_music/client.py | 18 ++++++++++++++++++ yandex_music/track/tracks_similar.py | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/yandex_music/client.py b/yandex_music/client.py index 45a445e..ee0164e 100644 --- a/yandex_music/client.py +++ b/yandex_music/client.py @@ -457,6 +457,8 @@ class Client(YandexMusicObject): :obj:`yandex_music.Supplement`: Объект класса `yandex_music.Supplement` представляющий дополнительную информацию о треке. + Raises: + :class:`yandex_music.YandexMusicError` """ url = f'{self.base_url}/tracks/{track_id}/supplement' @@ -468,6 +470,22 @@ class Client(YandexMusicObject): @log def tracks_similar(self, track_id: Union[str, int], timeout: Union[int, float] = None, *args, **kwargs) -> Optional: + """Получение похожих треков. + + Args: + track_id (:obj:`str`): Уникальный идентификатор трека. + timeout (:obj:`int` | :obj:`float`, optional): Если это значение указано, используется как время ожидания + ответа от сервера вместо указанного при создании пула. + **kwargs (:obj:`dict`, optional): Произвольные аргументы (будут переданы в запрос). + + Returns: + :obj:`yandex_music.TracksSimilar`: Объект класса `yandex_music.TracksSimilar` представляющий список похожих + треков на другой трек. + + Raises: + :class:`yandex_music.YandexMusicError` + """ + url = f'{self.base_url}/tracks/{track_id}/similar' result = self._request.get(url, timeout=timeout, *args, **kwargs) diff --git a/yandex_music/track/tracks_similar.py b/yandex_music/track/tracks_similar.py index c9e3e73..59e88bf 100644 --- a/yandex_music/track/tracks_similar.py +++ b/yandex_music/track/tracks_similar.py @@ -7,6 +7,24 @@ from yandex_music import YandexMusicObject class TracksSimilar(YandexMusicObject): + """Класс, представляющий список похожих треков на другой трек. + + Attributes: + track (:obj:`yandex_music.Track`): Объект класса :class:`yandex_music.Track` представляющий трек. + similar_tracks (:obj:`list` из :obj:`yandex_music.Track`): Список объектов класса + :class:`yandex_music.Track` представляющие похожие треки на `track`. + client (:obj:`yandex_music.Client`): Объект класса :class:`yandex_music.Client` представляющий клиент Yandex + Music. + + Args: + track (:obj:`yandex_music.Track`): Объект класса :class:`yandex_music.Track` представляющий трек. + similar_tracks (:obj:`list` из :obj:`yandex_music.Track`): Список объектов класса + :class:`yandex_music.Track` представляющие похожие треки на `track`. + client (:obj:`yandex_music.Client`, optional): Объект класса :class:`yandex_music.Client` представляющий клиент + Yandex Music. + **kwargs: Произвольные ключевые аргументы полученные от API. + """ + def __init__(self, track: Optional['Track'], similar_tracks: List['Track'], From 304fe1ed23e15783cecae0702be8eb78de5161ee Mon Sep 17 00:00:00 2001 From: Il`ya Date: Sat, 25 Jan 2020 20:03:00 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B,=20=D0=B8=D0=B7?= =?UTF-8?q?=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=BD=D0=BE=20=D0=B8=D0=BC=D1=8F?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0.=20#197?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_tracks_similar.py | 42 ++++++++++++++++++++++++++++ yandex_music/__init__.py | 4 +-- yandex_music/client.py | 6 ++-- yandex_music/track/tracks_similar.py | 6 ++-- 4 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 tests/test_tracks_similar.py diff --git a/tests/test_tracks_similar.py b/tests/test_tracks_similar.py new file mode 100644 index 0000000..05ae9db --- /dev/null +++ b/tests/test_tracks_similar.py @@ -0,0 +1,42 @@ +import pytest + +from yandex_music import SimilarTracks + + +@pytest.fixture(scope='class') +def similar_tracks(track): + return SimilarTracks(track, [track]) + + +class TestSimilarTracks: + def test_expected_values(self, similar_tracks, track): + assert similar_tracks.track == track + assert similar_tracks.similar_tracks == [track] + + def test_de_json_none(self, client): + assert SimilarTracks.de_json({}, client) is None + + def test_de_json_required(self, client, track): + json_dict = {'track': track.to_dict(), 'similar_tracks': [track.to_dict()]} + similar_tracks = SimilarTracks.de_json(json_dict, client) + + assert similar_tracks.track == track + assert similar_tracks.similar_tracks == [track] + + def test_de_json_all(self, client, track): + json_dict = {'track': track.to_dict(), 'similar_tracks': [track.to_dict()]} + similar_tracks = SimilarTracks.de_json(json_dict, client) + + assert similar_tracks.track == track + assert similar_tracks.similar_tracks == [track] + + def test_equality(self, track): + a = SimilarTracks(track, [track]) + b = SimilarTracks(None, [track]) + c = SimilarTracks(track, [track]) + + assert a != b + assert hash(a) != hash(b) + assert a is not b + + assert a == c diff --git a/yandex_music/__init__.py b/yandex_music/__init__.py index c70a79c..8e8b1c9 100644 --- a/yandex_music/__init__.py +++ b/yandex_music/__init__.py @@ -44,7 +44,7 @@ from .tracks_list import TracksList from .track.major import Major from .track.normalization import Normalization from .track.track import Track -from .track.tracks_similar import TracksSimilar +from .track.tracks_similar import SimilarTracks from .likes.albums_likes import AlbumsLikes from .likes.artists_likes import ArtistsLikes @@ -120,4 +120,4 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio 'Icon', 'Images', 'Id', 'Station', 'Dashboard', 'RotorSettings', 'AdParams', 'Restrictions', 'Value', 'Enum', 'DiscreteScale', 'StationResult', 'Sequence', 'StationTracksResult', 'BriefInfo', 'Description', 'PlaylistId', 'Vinyl', 'Supplement', 'Lyrics', 'VideoSupplement', 'ArtistTracks', 'Pager', 'ArtistAlbums', - 'PlaylistAbsence', 'Shot', 'ShotEvent', 'ShotType', 'ShotData', 'TracksSimilar'] + 'PlaylistAbsence', 'Shot', 'ShotEvent', 'ShotType', 'ShotData', 'SimilarTracks'] diff --git a/yandex_music/client.py b/yandex_music/client.py index ee0164e..c05c0dc 100644 --- a/yandex_music/client.py +++ b/yandex_music/client.py @@ -6,7 +6,7 @@ from typing import Callable, Union, List, Optional from yandex_music import YandexMusicObject, Status, Settings, PermissionAlerts, Experiments, Artist, Album, Playlist, \ TracksList, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed, PromoCodeStatus, DownloadInfo, Search, \ Suggestions, Landing, Genre, Dashboard, StationResult, StationTracksResult, BriefInfo, Supplement, ArtistTracks, \ - ArtistAlbums, ShotEvent, TracksSimilar + ArtistAlbums, ShotEvent, SimilarTracks from yandex_music.utils.request import Request from yandex_music.utils.difference import Difference from yandex_music.exceptions import InvalidToken, Captcha @@ -479,7 +479,7 @@ class Client(YandexMusicObject): **kwargs (:obj:`dict`, optional): Произвольные аргументы (будут переданы в запрос). Returns: - :obj:`yandex_music.TracksSimilar`: Объект класса `yandex_music.TracksSimilar` представляющий список похожих + :obj:`yandex_music.SimilarTracks`: Объект класса `yandex_music.SimilarTracks` представляющий список похожих треков на другой трек. Raises: @@ -490,7 +490,7 @@ class Client(YandexMusicObject): result = self._request.get(url, timeout=timeout, *args, **kwargs) - return TracksSimilar.de_json(result, self) + return SimilarTracks.de_json(result, self) @log def play_audio(self, diff --git a/yandex_music/track/tracks_similar.py b/yandex_music/track/tracks_similar.py index 59e88bf..0ac2ef4 100644 --- a/yandex_music/track/tracks_similar.py +++ b/yandex_music/track/tracks_similar.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: from yandex_music import YandexMusicObject -class TracksSimilar(YandexMusicObject): +class SimilarTracks(YandexMusicObject): """Класс, представляющий список похожих треков на другой трек. Attributes: @@ -37,11 +37,11 @@ class TracksSimilar(YandexMusicObject): self._id_attrs = (self.track, self.similar_tracks) @classmethod - def de_json(cls, data: dict, client: 'Client') -> Optional['TracksSimilar']: + def de_json(cls, data: dict, client: 'Client') -> Optional['SimilarTracks']: if not data: return None - data = super(TracksSimilar, cls).de_json(data, client) + data = super(SimilarTracks, cls).de_json(data, client) from yandex_music import Track data['track'] = Track.de_json(data.get('track'), client) data['similar_tracks'] = Track.de_list(data.get('similar_tracks'), client)