New supported objects: Response, PromoCodeStatus

The following method are wrapped: /account/consume-promo-code
Added error receiver
The following fields are optional: Ratings.day, InvocationInfo.exec_duration_millis, Account.registered_at
Request now accepts client object, not token
このコミットが含まれているのは:
Marshal 2019-05-16 15:45:25 +03:00
コミット 9a717e6196
9個のファイルの変更94行の追加25行の削除

ファイルの表示

@ -40,10 +40,11 @@ from .event_artist import EventArtist
from .event_album import EventAlbum
from .feed import Feed
from .event import Event
from .promo_code_status import PromoCodeStatus
__all__ = ['YandexMusicObject', 'Account', 'PassportPhone', 'InvocationInfo', 'Permissions', 'Plus', 'Subscription',
'Status', 'Price', 'Product', 'AutoRenewable', 'Settings', 'PermissionAlerts', 'Experiments', 'Cover',
'Ratings', 'Counts', 'Link', 'Artist', 'User', 'CaseForms', 'MadeFor', 'Label', 'Album', 'PlayCounter',
'Playlist', 'TrackShort', 'TracksLikes', 'Major', 'Normalization', 'TrackPosition', 'Track', 'AlbumsLikes',
'ArtistsLikes', 'PlaylistsLikes', 'GeneratedPlaylist', 'TrackWithAds', 'Day', 'EventArtist', 'EventAlbum',
'Feed', 'Event']
'Feed', 'Event', 'PromoCodeStatus']

ファイルの表示

@ -17,7 +17,7 @@ class Account(YandexMusicObject):
service_available,
hosted_user,
passport_phones,
registered_at,
registered_at=None,
has_info_for_app_metrica=False,
client=None,
**kwargs):
@ -33,7 +33,8 @@ class Account(YandexMusicObject):
self.service_available = service_available
self.hosted_user = hosted_user
self.passport_phones = passport_phones
self.registered_at = datetime.fromisoformat(registered_at)
self.registered_at = datetime.fromisoformat(registered_at) if registered_at else registered_at
self.has_info_for_app_metrica = has_info_for_app_metrica
self.client = client

ファイルの表示

@ -1,7 +1,7 @@
import logging
from yandex_music import YandexMusicObject, Status, Settings, PermissionAlerts, Experiments, Artist, Album, Playlist, \
TracksLikes, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed
TracksLikes, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed, PromoCodeStatus
from yandex_music.utils.request import Request
from yandex_music.error import InvalidToken
@ -9,7 +9,7 @@ from yandex_music.error import InvalidToken
class Client(YandexMusicObject):
def __init__(self, token, base_url=None, request=None):
self.token = token
self._request = request or Request(token)
self._request = request or Request(self)
self.logger = logging.getLogger(__name__)
if base_url is None:
@ -78,6 +78,15 @@ class Client(YandexMusicObject):
return feed
def consume_promo_code(self, code: str, language='en', timeout=None, *args, **kwargs):
url = f'{self.base_url}/account/consume-promo-code'
result = self._request.post(url, {'code': code, 'language': language}, timeout=timeout, *args, **kwargs)
promo_code_status = PromoCodeStatus.de_json(result, self)
return promo_code_status
def artists(self, artist_ids: list or int or str, timeout=None, *args, **kwargs):
url = f'{self.base_url}/artists'

ファイルの表示

@ -5,11 +5,12 @@ class InvocationInfo(YandexMusicObject):
def __init__(self,
hostname,
req_id,
exec_duration_millis,
exec_duration_millis=None,
client=None,
**kwargs):
self.hostname = hostname
self.req_id = req_id
self.exec_duration_millis = exec_duration_millis
self.client = client

26
yandex_music/promo_code_status.py ノーマルファイル
ファイルの表示

@ -0,0 +1,26 @@
from yandex_music import YandexMusicObject
class PromoCodeStatus(YandexMusicObject):
def __init__(self,
status,
status_desc,
account_status,
client=None,
**kwargs):
self.status = status
self.status_desc = status_desc
self.account_status = account_status
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(PromoCodeStatus, cls).de_json(data, client)
from yandex_music import Status
data['account_status'] = Status.de_json(data.get('account_status'), client)
return cls(client=client, **data)

ファイルの表示

@ -5,11 +5,12 @@ class Ratings(YandexMusicObject):
def __init__(self,
week,
month,
day,
day=None,
client=None,
**kwargs):
self.week = week
self.month = month
self.day = day
self.client = client

ファイルの表示

@ -1,4 +1,4 @@
from yandex_music import YandexMusicObject, Account, Permissions, Plus, Subscription
from yandex_music import YandexMusicObject
class Status(YandexMusicObject):
@ -10,7 +10,7 @@ class Status(YandexMusicObject):
subeditor,
subeditor_level,
plus,
default_email,
default_email=None,
client=None,
**kwargs):
self.account = account
@ -20,6 +20,7 @@ class Status(YandexMusicObject):
self.subeditor = subeditor
self.subeditor_level = subeditor_level
self.plus = plus
self.default_email = default_email
self.client = client
@ -31,6 +32,7 @@ class Status(YandexMusicObject):
return None
data = super(Status, cls).de_json(data, client)
from yandex_music import Account, Permissions, Plus, Subscription
data['account'] = Account.de_json(data.get('account'), client)
data['permissions'] = Permissions.de_json(data.get('permissions'), client)
data['subscription'] = Subscription.de_json(data.get('subscription'), client)

ファイルの表示

@ -3,6 +3,7 @@ import json
import logging
import requests
from yandex_music.utils.response import Response
from yandex_music.error import Unauthorized, BadRequest, NetworkError, YandexMusicError
@ -18,12 +19,14 @@ HEADERS = {
class Request(object):
def __init__(self,
token,
client,
headers=None,
proxies=None):
self.client = client
self.headers = headers or HEADERS
self.headers.update({'Authorization': f'OAuth {token}'})
self.headers.update({'Authorization': f'OAuth {self.client.token}'})
self.proxies = proxies # TODO
@ -41,8 +44,7 @@ class Request(object):
return cleaned_object
@staticmethod
def _parse(json_data):
def _parse(self, json_data) -> Response:
try:
decoded_s = json_data.decode('utf-8')
data = json.loads(decoded_s, object_hook=Request._object_hook)
@ -50,10 +52,10 @@ class Request(object):
logging.getLogger(__name__).debug(
'Logging raw invalid UTF-8 response:\n%r', json_data)
raise YandexMusicError('Server response could not be decoded using UTF-8')
except ValueError:
raise Exception('Invalid server response')
except (AttributeError, ValueError):
raise YandexMusicError('Invalid server response')
return data.get('result')
return Response.de_json(data, self.client)
def _request_wrapper(self, *args, **kwargs):
if 'headers' not in kwargs:
@ -65,14 +67,16 @@ class Request(object):
resp = requests.request(verify=False, *args, **kwargs)
except requests.Timeout:
raise TimeoutError()
except requests.RequestException:
raise Exception('Network error')
except requests.RequestException as e:
raise NetworkError(e)
if 200 <= resp.status_code <= 299:
return resp.content
return self._parse(resp.content).result
try:
message = self._parse(resp.text)
message = self._parse(resp.content).error
if message is None:
raise ValueError()
except ValueError:
message = 'Unknown HTTPError'
@ -81,7 +85,7 @@ class Request(object):
elif resp.status_code == 400:
raise BadRequest(message)
elif resp.status_code in (404, 409, 413):
raise NetworkError()
raise NetworkError(message)
elif resp.status_code == 502:
raise NetworkError('Bad Gateway')
@ -89,10 +93,8 @@ class Request(object):
raise NetworkError('{0} ({1})'.format(message, resp.status_code))
def get(self, url, timeout=5, *args, **kwargs):
result = self._request_wrapper('GET', url, headers=self.headers, timeout=timeout, *args, **kwargs)
return self._parse(result)
return self._request_wrapper('GET', url, headers=self.headers, timeout=timeout, *args, **kwargs)
def post(self, url, data, timeout=5, *args, **kwargs):
result = self._request_wrapper('POST', url, headers=self.headers, data=data, timeout=timeout, *args, **kwargs)
return self._parse(result)
return self._request_wrapper('POST', url, headers=self.headers, data=data, timeout=timeout, *args, **kwargs)

26
yandex_music/utils/response.py ノーマルファイル
ファイルの表示

@ -0,0 +1,26 @@
from yandex_music import YandexMusicObject
class Response(YandexMusicObject):
def __init__(self,
invocation_info,
result=None,
error=None,
client=None,
**kwargs):
self.invocation_info = invocation_info
self.result = result
self.error = error
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Response, cls).de_json(data, client)
from yandex_music import InvocationInfo
data['invocation_info'] = InvocationInfo.de_json(data.get('invocation_info'), client)
return cls(client=client, **data)