Переезд на ruff и ruff format (#625)

このコミットが含まれているのは:
Ilya Siamionau 2023-11-17 22:10:37 +01:00 committed by GitHub
コミット 07b30cb0b9
この署名に対応する既知のキーがデータベースに存在しません
GPGキーID: 4AEE18F83AFDEB23
130個のファイルの変更546行の追加547行の削除

ファイルの表示

@ -1,25 +0,0 @@
name: Black
on: [ pull_request ]
jobs:
black:
runs-on: ubuntu-latest
steps:
- name: Checkout repository.
uses: actions/checkout@v4
- name: Setup Python.
uses: actions/setup-python@v4
with:
python-version: 3.7
- name: Install dependencies.
run: pip install black
- name: Check code style of tests.
run: black --config=black.toml --check tests
- name: Check code style of package.
run: black --config=black.toml --check yandex_music

29
.github/workflows/ruff.yml vendored ノーマルファイル
ファイルの表示

@ -0,0 +1,29 @@
name: Linter and code style check
on: [ pull_request ]
permissions:
contents: read
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- name: Checkout repository.
uses: actions/checkout@v4
- name: Setup Python.
uses: actions/setup-python@v4
with:
python-version: 3.7
- name: Run linter check.
uses: chartboost/ruff-action@v1
with:
version: 0.1.6
- name: Run code style check.
uses: chartboost/ruff-action@v1
with:
version: 0.1.6
args: format --check

ファイルの表示

@ -39,17 +39,17 @@ PR'ы должны быть сделаны в `main` ветку. Определ
## Форматирование кода (стиль написания)
В проекте используется `black`. Не забывайте перед публикацией отформатировать код и проверить его на работоспособность. Используются одинарные кавычки. Запускайте `black` с конфигом из основной директории:
В проекте используется `ruff`. Не забывайте перед публикацией отформатировать код и проверить его на работоспособность. Используются одинарные кавычки.
Запуск линтера:
```shell
black --config=black.toml yandex_music
ruff .
```
или
Запуск форматера:
```shell
make black
```
ruff format .
````
## Создание новых моделей
@ -94,4 +94,4 @@ _Используйте WSL если вы на Windows._
make all
```
Выполнит за вас black для основного модуля и тестов, сгенерирует асинхронную версию клиента, сгенерирует camel case псевдонимы.
Выполнит за вас ruff и ruff format, сгенерирует асинхронную версию клиента, сгенерирует camel case псевдонимы.

ファイルの表示

@ -1,10 +1,10 @@
# makefile for Yandex Music project
black:
black --config=black.toml yandex_music
ruff:
ruff . --fix
black_test:
black --config=black.toml tests
ruff_format:
ruff format .
gen_async:
python generate_async_version.py
@ -15,17 +15,11 @@ gen_alias:
gen:
make gen_async && make gen_alias
b:
make black
bt:
make black_test
g:
make gen
all:
make g && make b && make bt
make g && make ruff && make ruff_format
a:
make all

ファイルの表示

@ -1,21 +0,0 @@
[tool.black]
line-length = 120
skip-string-normalization=true
target-version = ['py37']
include = '\.pyi?$'
exclude = '''
(
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
)/
)
'''

ファイルの表示

@ -49,7 +49,7 @@ exclude_patterns = []
myst_heading_anchors = 4
# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html?highlight=header-anchors#code-fences-using-colons
myst_enable_extensions = ["colon_fence"]
myst_enable_extensions = ['colon_fence']
# TODO add substitution https://myst-parser.readthedocs.io/en/latest/syntax/optional.html?highlight=header-anchors#substitutions-with-jinja2
# -- Options for HTML output -------------------------------------------------

ファイルの表示

@ -2,7 +2,6 @@ import os
from yandex_music import Client
CHART_ID = 'world'
TOKEN = os.environ.get('TOKEN')

ファイルの表示

@ -1,5 +1,6 @@
import sys
import datetime
import sys
from yandex_music.client import Client
# Help text
@ -19,7 +20,7 @@ DailyPlaylist = next(
# Check if we don't need to update it
if DailyPlaylist.play_counter.updated:
modifiedDate = datetime.datetime.strptime(DailyPlaylist.modified, "%Y-%m-%dT%H:%M:%S%z").date()
modifiedDate = datetime.datetime.strptime(DailyPlaylist.modified, '%Y-%m-%dT%H:%M:%S%z').date()
if datetime.datetime.now().date() == modifiedDate:
print('\x1b[6;30;43m' + 'Looks like it has been already updated today' + '\x1b[0m')
quit()

ファイルの表示

@ -2,7 +2,6 @@ import os
from yandex_music import Client
TOKEN = os.environ.get('TOKEN')
ALBUM_ID = 2832563

ファイルの表示

@ -3,7 +3,6 @@ import os
from yandex_music import Client
from yandex_music.exceptions import NotFoundError
TOKEN = os.environ.get('TOKEN')
client = Client(TOKEN).init()

ファイルの表示

@ -1,10 +1,10 @@
#!/usr/bin/env python3
import sys
import argparse
import re
from time import sleep
from subprocess import call
import sys
from pathlib import Path
from subprocess import call
from time import sleep
from typing import List
from yandex_music import Client
@ -22,7 +22,7 @@ parser.add_argument('--shuffle', action='store_true', help='randomize tracks ord
parser.add_argument(
'--token', default=DEFAULT_CACHE_FOLDER / CONFIG_NAME, help='YM API token as string or path to file'
)
parser.add_argument('--no-save-token', action='store_true', help='do\'nt save token in cache folder')
parser.add_argument('--no-save-token', action='store_true', help="do'nt save token in cache folder")
parser.add_argument('--cache-folder', type=Path, default=DEFAULT_CACHE_FOLDER, help='cached tracks folder')
parser.add_argument('--audio-player', default='cvlc', help='player to use')
parser.add_argument(
@ -43,7 +43,7 @@ if args.print_args:
print(args)
sys.exit()
if type(args.token) is str and re.match(r'^[A-Za-z0-9]{39}$', args.token):
if isinstance(args.token, str) and re.match(r'^[A-Za-z0-9]{39}$', args.token):
if not args.no_save_token:
parser.get_default('token').write_text(args.token)
else:
@ -62,7 +62,7 @@ if client.me.account.now and client.me.account.now.split('T')[0] == client.me.ac
if args.playlist == 'user':
user_playlists = client.users_playlists_list()
if not args.playlist_name:
print('specify --playlist-name', list(p.title for p in user_playlists))
print('specify --playlist-name', [p.title for p in user_playlists])
sys.exit(1)
playlist = next((p for p in user_playlists if p.title == args.playlist_name), None)
if playlist is None:
@ -82,7 +82,7 @@ if args.shuffle:
shuffle(tracks.tracks)
error_count = 0
for (i, short_track) in enumerate(tracks):
for i, short_track in enumerate(tracks):
if args.skip and args.skip > i:
continue

ファイルの表示

@ -9,7 +9,7 @@ proxied_request = Request(proxy_url=os.environ.get('PROXY_URL'))
try:
if not yandex_music_token:
raise YandexMusicError()
raise YandexMusicError
# подключаемся без прокси для получения информации об аккаунте (доступно из других стран)
client = Client(yandex_music_token, request=Request()).init()

ファイルの表示

@ -60,7 +60,7 @@ class Radio:
def __send_play_start_track(self, track, play_id):
total_seconds = track.duration_ms / 1000
self.client.play_audio(
from_="desktop_win-home-playlist_of_the_day-playlist-default",
from_='desktop_win-home-playlist_of_the_day-playlist-default',
track_id=track.id,
album_id=track.albums[0].id,
play_id=play_id,
@ -77,7 +77,7 @@ class Radio:
played_seconds = track.duration_ms / 1000
total_seconds = track.duration_ms / 1000
self.client.play_audio(
from_="desktop_win-home-playlist_of_the_day-playlist-default",
from_='desktop_win-home-playlist_of_the_day-playlist-default',
track_id=track.id,
album_id=track.albums[0].id,
play_id=play_id,
@ -91,8 +91,7 @@ class Radio:
self.client.rotor_station_feedback_track_finished(
station=self.station_id, track_id=track.id, total_played_seconds=played_seconds, batch_id=batch_id
)
pass
@staticmethod
def __generate_play_id():
return "%s-%s-%s" % (int(random() * 1000), int(random() * 1000), int(random() * 1000))
return '%s-%s-%s' % (int(random() * 1000), int(random() * 1000), int(random() * 1000))

ファイルの表示

@ -2,10 +2,10 @@ from math import floor
from random import random
from time import sleep
from yandex_music import Client
from radio import Radio
from yandex_music import Client
# API instance
client = Client(token='YOUR_TOKEN_HERE')

ファイルの表示

@ -1,9 +1,9 @@
from time import sleep
from yandex_music import Client
from radio import Radio
from yandex_music import Client
# API instance
client = Client(token='YOUR_API_KEY_HERE').init()

ファイルの表示

@ -1,6 +1,5 @@
from yandex_music import Client
client = Client().init()
type_to_name = {
@ -15,7 +14,7 @@ type_to_name = {
}
def send_search_request_and_print_result(query):
def send_search_request_and_print_result(query): # noqa: C901
search_result = client.search(query)
text = [f'Результаты по запросу "{query}":', '']
@ -35,7 +34,7 @@ def send_search_request_and_print_result(query):
elif type_ == 'artist':
best_result_text = best.name
elif type_ in ['album', 'podcast']:
best_result_text = best.title
best_result_text = best.title # noqa: SIM114
elif type_ == 'playlist':
best_result_text = best.title
elif type_ == 'video':

ファイルの表示

@ -1,8 +1,7 @@
#!/usr/bin/env python3
import subprocess
DISCLAIMER = '# THIS IS AUTO GENERATED COPY OF client.py. DON\'T EDIT IN BY HANDS #'
DISCLAIMER = "# THIS IS AUTO GENERATED COPY OF client.py. DON'T EDIT IN BY HANDS #"
DISCLAIMER = f'{"#" * len(DISCLAIMER)}\n{DISCLAIMER}\n{"#" * len(DISCLAIMER)}\n\n'
REQUEST_METHODS = ('_request_wrapper', 'get', 'post', 'retrieve', 'download')
@ -18,7 +17,7 @@ def gen_request(output_request_filename):
code = code.replace('resp.content', 'content')
code = code.replace(
'resp = requests.request(*args, **kwargs)',
f'async with aiohttp.request(*args, **kwargs) as _resp:\n{" " * 16}resp = _resp\n{" " * 16}content = await resp.content.read()',
f'async with aiohttp.request(*args, **kwargs) as _resp:\n{" " * 16}resp = _resp\n{" " * 16}content = await resp.content.read()', # noqa: E501
)
code = code.replace('except requests.Timeout', 'except asyncio.TimeoutError')
@ -32,7 +31,7 @@ def gen_request(output_request_filename):
code = code.replace('proxies=self.proxies', 'proxy=self.proxy_url')
code = code.replace(
"kwargs['timeout'] = self._timeout",
f"kwargs['timeout'] = aiohttp.ClientTimeout(total=self._timeout)\n{' ' * 8}else:\n{' ' * 12}kwargs['timeout'] = aiohttp.ClientTimeout(total=kwargs['timeout'])",
f"kwargs['timeout'] = aiohttp.ClientTimeout(total=self._timeout)\n{' ' * 8}else:\n{' ' * 12}kwargs['timeout'] = aiohttp.ClientTimeout(total=kwargs['timeout'])", # noqa: E501
)
# download method
@ -85,4 +84,6 @@ if __name__ == '__main__':
gen_client(client_filename)
for file in (request_filename, client_filename):
subprocess.run(['black', '--config', 'black.toml', file])
subprocess.run(['ruff', 'format', '--quiet', file]) # noqa: S603, S607
subprocess.run(['ruff', '--quiet', '--fix', file]) # noqa: S603, S607
subprocess.run(['ruff', 'format', '--quiet', file]) # noqa: S603, S607

ファイルの表示

@ -1,14 +1,14 @@
#!/usr/bin/env python3
import os
import ast
import os
SOURCE_FOLDER = 'yandex_music'
EXCLUDED_FUNCTIONS = {'de_dict', 'de_json', 'de_list', 'de_json_async', 'de_list_async'}
ALIAS_TEMPLATE = '''
ALIAS_TEMPLATE = """
#: Псевдоним для :attr:`{name}`
{camel_case_name} = {name}
'''
"""
ALIAS_SECTION_MARKER = ' # camelCase псевдонимы'
@ -38,9 +38,8 @@ def _generate_code(function_name: str, intent=0) -> str:
code_lines = [line for line in code.split('\n') if line]
code_lines = [f'{" " * intent}{line}' for line in code_lines]
code = '\n'.join(code_lines)
return code
return '\n'.join(code_lines)
def _process_file(file: str) -> None:
@ -52,10 +51,9 @@ def _process_file(file: str) -> None:
if isinstance(node, ast.ClassDef):
count_of_class_def += 1
if isinstance(node, ast.FunctionDef) or isinstance(node, ast.AsyncFunctionDef):
if _validate_function_name(node.name):
alias_code = _generate_code(node.name, node.col_offset)
file_aliases_code_fragments.append(alias_code)
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and _validate_function_name(node.name):
alias_code = _generate_code(node.name, node.col_offset)
file_aliases_code_fragments.append(alias_code)
# there are no such cases in data models yet
# only in yandex_music/exceptions.py and yandex_music/utils/difference.py
@ -76,7 +74,7 @@ def _process_file(file: str) -> None:
return
# remove prev aliases
file_code_lines = file_code_lines[:marker_lineno + 1]
file_code_lines = file_code_lines[: marker_lineno + 1]
file_code_lines.append('')
file_code_lines.extend(file_aliases_code_fragments)
file_code_lines.append('')

ファイルの表示

@ -3,7 +3,7 @@ requests
aiohttp
aiofiles
# rly dev
black
ruff==0.1.6
coverage
pytest
pytest-cov

54
ruff.toml ノーマルファイル
ファイルの表示

@ -0,0 +1,54 @@
extend-select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort
"C90", # flake8-comprehensions
"B", # flake8-bugbear
"Q", # flake8-quotes
"S", # flake8-bandit
"ASYNC", # flake8-async
# "ANN", # flake8-annotations. Not all resolved yet
"C",
"BLE",
"ERA",
"ICN",
"INP",
"ISC",
"NPY",
"PGH",
"PIE",
"RET",
"RSE",
"SIM",
"T20",
"TCH",
"TID",
"YTT",
]
line-length = 120
target-version = "py37"
ignore = [
"PGH004", # use specific rule code with noqa; works bad with JetBrains IDE Warnings
"ANN002", # Missing type annotation for `*args`
"ANN003", # Missing type annotation for `**kwargs`
"ANN101", # Missing type annotation for `self` in method
"ANN102", # Missing type annotation for `cls` in classmethod
]
[per-file-ignores]
"examples/*.py" = ["T201", "S311", "ERA001", "INP001", "S106", "BLE001", "S603"]
"docs/source/conf.py" = ["INP001"]
"tests/*.py" = ["S101"] # Use of assert
"tests/__init__.py" = ["F401"] # Unused import
"yandex_music/__init__.py" = ["I001"] # Import sort
"yandex_music/client*.py" = ["T201"] # print
"test.py" = ["S101", "ERA001", "T201", "E501", "F401", "F841"]
[flake8-quotes]
docstring-quotes = "double"
multiline-quotes = "double"
inline-quotes = "single"
[format]
quote-style = "single"

ファイルの表示

@ -1,7 +1,7 @@
import re
import sys
from setuptools import setup, find_packages
from setuptools import find_packages, setup
from setuptools.command.test import test
@ -41,20 +41,20 @@ setup(
'Operating System :: OS Independent',
'Topic :: Internet',
'Topic :: Multimedia :: Sound/Audio',
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Libraries :: Application Frameworks",
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Software Development :: Libraries :: Application Frameworks',
'Programming Language :: Python',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
"Programming Language :: Python :: Implementation",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
'Programming Language :: Python :: Implementation',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],
python_requires="~=3.7",
python_requires='~=3.7',
cmdclass={'test': PyTest},
tests_require=['pytest'],
project_urls={

ファイルの表示

@ -2,24 +2,32 @@ from .test_account import TestAccount
from .test_ad_params import TestAdParams
from .test_album import TestAlbum
from .test_album_event import TestAlbumEvent
from .test_alert import TestAlert
from .test_alert_button import TestAlertButton
from .test_artist import TestArtist
from .test_artist_event import TestArtistEvent
from .test_auto_renewable import TestAutoRenewable
from .test_best import TestBest
from .test_block import TestBlock
from .test_block_entity import TestBlockEntity
from .test_brand import TestBrand
from .test_case_forms import TestCaseForms
from .test_chart import TestChart
from .test_chart_info import TestChartInfo
from .test_chart_info_menu import TestChartInfoMenu
from .test_chart_info_menu_item import TestChartInfoMenuItem
from .test_contest import TestContest
from .test_context import TestContext
from .test_counts import TestCounts
from .test_cover import TestCover
from .test_custom_wave import TestCustomWave
from .test_day import TestDay
from .test_deactivation import TestDeactivation
from .test_deprecation import TestDeprecation
from .test_description import TestDescription
from .test_discrete_scale import TestDiscreteScale
from .test_enum import TestEnum
from .test_event import TestEvent
from .test_chart_info_menu_item import TestChartInfoMenuItem
from .test_chart_info_menu import TestChartInfoMenu
from .test_chart_info import TestChartInfo
from .test_generated_playlist import TestGeneratedPlaylist
from .test_genre import TestGenre
from .test_icon import TestIcon
@ -27,13 +35,19 @@ from .test_id import TestId
from .test_images import TestImages
from .test_invocation_info import TestInvocationInfo
from .test_label import TestLabel
from .test_link import TestLink
from .test_licence_text_part import TestLicenceTextPart
from .test_link import TestLink
from .test_lyrics import TestLyrics
from .test_lyrics_info import TestLyricsInfo
from .test_lyrics_major import TestLyricsMajor
from .test_made_for import TestMadeFor
from .test_major import TestMajor
from .test_meta_data import TestMetaData
from .test_mix_link import TestMixLink
from .test_non_auto_renewable import TestNonAutoRenewable
from .test_normalization import TestNormalization
from .test_open_graph_data import TestOpenGraphData
from .test_operator import TestOperator
from .test_pager import TestPager
from .test_passport_phone import TestPassportPhone
from .test_permissions import TestPermissions
@ -44,57 +58,40 @@ from .test_play_counter import TestPlayCounter
from .test_playlist import TestPlaylist
from .test_playlist_absence import TestPlaylistAbsence
from .test_playlist_id import TestPlaylistId
from .test_playlist_id import TestPlaylistId
from .test_plus import TestPlus
from .test_poetry_lover_match import TestPoetryLoverMatch
from .test_price import TestPrice
from .test_product import TestProduct
from .test_promotion import TestPromotion
from .test_queue_item import TestQueueItem
from .test_r128 import TestR128
from .test_ratings import TestRatings
from .test_renewable_remainder import TestRenewableRemainder
from .test_restrictions import TestRestrictions
from .test_rotor_settings import TestRotorSettings
from .test_search_result import TestSearchResult
from .test_sequence import TestSequence
from .test_settings import TestSettings
from .test_shot import TestShot
from .test_shot_data import TestShotData
from .test_shot_type import TestShotType
from .test_station import TestStation
from .test_station_data import TestStationData
from .test_station_result import TestStationResult
from .test_status import TestStatus
from .test_subscription import TestSubscription
from .test_suggestions import TestSuggestions
from .test_tag import TestTag
from .test_title import TestTitle
from .test_track import TestTrack
from .test_track_id import TestTrackId
from .test_track_lyrics import TestTrackLyrics
from .test_track_position import TestTrackPosition
from .test_track_short import TestTrackShort
from .test_track_short_old import TestTrackShortOld
from .test_track_with_ads import TestTrackWithAds
from .test_user import TestUser
from .test_value import TestValue
from .test_value import TestValue
from .test_video import TestVideo
from .test_video_supplement import TestVideoSupplement
from .test_vinyl import TestVinyl
from .test_shot_type import TestShotType
from .test_shot_data import TestShotData
from .test_shot import TestShot
from .test_renewable_remainder import TestRenewableRemainder
from .test_tag import TestTag
from .test_meta_data import TestMetaData
from .test_licence_text_part import TestLicenceTextPart
from .test_station_data import TestStationData
from .test_alert_button import TestAlertButton
from .test_alert import TestAlert
from .test_non_auto_renewable import TestNonAutoRenewable
from .test_poetry_lover_match import TestPoetryLoverMatch
from .test_deactivation import TestDeactivation
from .test_operator import TestOperator
from .test_contest import TestContest
from .test_open_graph_data import TestOpenGraphData
from .test_brand import TestBrand
from .test_context import TestContext
from .test_queue_item import TestQueueItem
from .test_deprecation import TestDeprecation
from .test_lyrics_major import TestLyricsMajor
from .test_track_lyrics import TestTrackLyrics
from .test_custom_wave import TestCustomWave
from .test_r128 import TestR128
from .test_lyrics_info import TestLyricsInfo

ファイルの表示

@ -1,16 +1,20 @@
import pytest
from yandex_music import (
R128,
Account,
AdParams,
Album,
AlbumEvent,
Alert,
AlertButton,
Artist,
ArtistEvent,
AutoRenewable,
Best,
Block,
BlockEntity,
Brand,
CaseForms,
Chart,
ChartInfo,
@ -18,10 +22,14 @@ from yandex_music import (
ChartInfoMenuItem,
ChartItem,
Client,
Contest,
Context,
Counts,
Cover,
CustomWave,
Day,
Deactivation,
Deprecation,
Description,
DiscreteScale,
Enum,
@ -35,11 +43,16 @@ from yandex_music import (
LicenceTextPart,
Link,
Lyrics,
LyricsInfo,
LyricsMajor,
MadeFor,
Major,
MetaData,
MixLink,
NonAutoRenewable,
Normalization,
OpenGraphData,
Operator,
Pager,
PassportPhone,
Permissions,
@ -51,6 +64,7 @@ from yandex_music import (
PlaylistAbsence,
PlaylistId,
Plus,
PoetryLoverMatch,
Price,
Product,
Promotion,
@ -65,6 +79,7 @@ from yandex_music import (
ShotData,
ShotType,
Station,
StationData,
StationResult,
Status,
Subscription,
@ -72,6 +87,7 @@ from yandex_music import (
Title,
Track,
TrackId,
TrackLyrics,
TrackPosition,
TrackShort,
TrackShortOld,
@ -81,40 +97,33 @@ from yandex_music import (
Video,
VideoSupplement,
Vinyl,
StationData,
AlertButton,
Alert,
NonAutoRenewable,
PoetryLoverMatch,
Deactivation,
Operator,
Contest,
OpenGraphData,
Brand,
Context,
Deprecation,
TrackLyrics,
LyricsMajor,
R128,
LyricsInfo,
)
from . import (
TestAccount,
TestAdParams,
TestAlbum,
TestAlert,
TestAlertButton,
TestArtist,
TestArtistEvent,
TestAutoRenewable,
TestBest,
TestBlock,
TestBlockEntity,
TestBrand,
TestCaseForms,
TestChart,
TestChartInfo,
TestChartInfoMenuItem,
TestContest,
TestContext,
TestCounts,
TestCover,
TestCustomWave,
TestDay,
TestDeactivation,
TestDeprecation,
TestDescription,
TestDiscreteScale,
TestEnum,
@ -128,10 +137,15 @@ from . import (
TestLicenceTextPart,
TestLink,
TestLyrics,
TestLyricsInfo,
TestLyricsMajor,
TestMajor,
TestMetaData,
TestMixLink,
TestNonAutoRenewable,
TestNormalization,
TestOpenGraphData,
TestOperator,
TestPager,
TestPassportPhone,
TestPermissions,
@ -142,9 +156,11 @@ from . import (
TestPlaylistAbsence,
TestPlaylistId,
TestPlus,
TestPoetryLoverMatch,
TestPrice,
TestProduct,
TestPromotion,
TestR128,
TestRatings,
TestRenewableRemainder,
TestRotorSettings,
@ -155,6 +171,7 @@ from . import (
TestShotData,
TestShotType,
TestStation,
TestStationData,
TestStationResult,
TestStatus,
TestSubscription,
@ -162,6 +179,7 @@ from . import (
TestTitle,
TestTrack,
TestTrackId,
TestTrackLyrics,
TestTrackPosition,
TestTrackShort,
TestTrackShortOld,
@ -171,23 +189,6 @@ from . import (
TestVideo,
TestVideoSupplement,
TestVinyl,
TestArtistEvent,
TestStationData,
TestAlertButton,
TestAlert,
TestNonAutoRenewable,
TestPoetryLoverMatch,
TestDeactivation,
TestOperator,
TestContest,
TestOpenGraphData,
TestBrand,
TestContext,
TestDeprecation,
TestLyricsMajor,
TestTrackLyrics,
TestR128,
TestLyricsInfo,
)
@ -742,11 +743,6 @@ def playlist_absence():
return PlaylistAbsence(TestPlaylistAbsence.kind, TestPlaylistAbsence.reason)
@pytest.fixture(scope='session')
def results(playlist):
return [playlist]
@pytest.fixture(scope='session')
def context():
return Context(TestContext.type_, TestContext.id_, TestContext.description)

ファイルの表示

@ -112,10 +112,10 @@ class TestAlbum:
def test_de_json_required(self, client):
json_dict = {'id': self.id}
album = Album.de_json(json_dict, client)
Album.de_json(json_dict, client)
def test_de_json_all(self, client, artist, label, track_position, track, album_without_nested_albums, deprecation):
labels = [label] if type(label) == str else [label.to_dict()]
labels = [label] if isinstance(label, str) else [label.to_dict()]
json_dict = {
'id': self.id,
'error': self.error,

ファイルの表示

@ -64,7 +64,7 @@ class TestChartInfo:
self.id, self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
)
b = ChartInfo(
"no_id", self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
'no_id', self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist
)
c = ChartInfo(
self.id, self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu, playlist

ファイルの表示

@ -19,7 +19,7 @@ class TestChartInfoMenu:
def test_equality(self, chart_info_menu_item):
a = ChartInfoMenu([chart_info_menu_item])
b = ChartInfoMenu([ChartInfoMenuItem("tt", "no_url")])
b = ChartInfoMenu([ChartInfoMenuItem('tt', 'no_url')])
c = ChartInfoMenu([chart_info_menu_item])
assert a != b

ファイルの表示

@ -40,7 +40,7 @@ class TestChartInfoMenuItem:
def test_equality(self):
a = ChartInfoMenuItem(self.title, self.url, self.selected)
b = ChartInfoMenuItem(self.title, "no_url", self.selected)
b = ChartInfoMenuItem(self.title, 'no_url', self.selected)
c = ChartInfoMenuItem(self.title, self.url, self.selected)
assert a != b

ファイルの表示

@ -38,7 +38,7 @@ class TestCover:
def test_de_json_required(self, client):
json_dict = {}
cover = Cover.de_json(json_dict, client)
Cover.de_json(json_dict, client)
def test_de_json_all(self, client):
json_dict = {

ファイルの表示

@ -1,5 +1,3 @@
import pytest
from yandex_music import CustomWave

ファイルの表示

@ -53,7 +53,7 @@ class TestGenre:
assert genre.weight == self.weight
assert genre.composer_top == self.composer_top
assert genre.title == self.title
assert genre.titles == {"uz": title}
assert genre.titles == {'uz': title}
assert genre.images == images
assert genre.show_in_menu == self.show_in_menu
assert genre.show_in_regions == self.show_in_regions

ファイルの表示

@ -14,7 +14,7 @@ class TestImages:
def test_de_json_required(self, client):
json_dict = {}
images = Images.de_json(json_dict, client)
Images.de_json(json_dict, client)
def test_de_json_all(self, client):
json_dict = {'_208x208': self._208x208, '_300x300': self._300x300}

ファイルの表示

@ -8,7 +8,7 @@ class TestLabel:
another_representation_of_label = 'NoCopyrightSounds'
def test_expected_values(self, label):
if type(label) == str:
if isinstance(label, str):
assert label == self.another_representation_of_label
else:
assert label.id == self.id

ファイルの表示

@ -8,19 +8,19 @@ class TestLyrics:
'Too big, too small?\nSize does matter, after all\nZu groß, zu klein?\nEr könnte etwas größer '
'sein\n\nMercedes-Benz und Autobahn\nAlleine in das Ausland fahren\nReise, '
'Reise! Fahrvergnügen\nIch will nur Spaß, mich nicht verlieben\n\nJust a little bit...\nJust a '
'little, bitch!\n\nYou\'ve got a pussy\nI have a dick, ah.\nSo what\'s the problem?\nLet\'s do it '
'quick!\n\nSo take me now, before it\'s too late\nLife\'s too short, so I can\'t wait\nTake me now! '
'Oh, don\'t you see?\nI can\'t get laid in Germany…\n\nToo short, too tall?\nDoesn\'t matter, '
"little, bitch!\n\nYou've got a pussy\nI have a dick, ah.\nSo what's the problem?\nLet's do it "
"quick!\n\nSo take me now, before it's too late\nLife's too short, so I can't wait\nTake me now! "
"Oh, don't you see?\nI can't get laid in Germany…\n\nToo short, too tall?\nDoesn't matter, "
'one size fits all\nZu groß, zu klein?\nDer Schlagbaum sollte oben sein\n\nSchönes Fräulein, '
'Lust auf mehr\nBlitzkrieg mit dem Fleischgewehr\nSchnaps im Kopf, du holde Braut\nSteck Bratwurst '
'in dein Sauerkraut\n\nJust a little bit...\nBe my little bitch!\n\nYou\'ve got a pussy\nI have a '
'dick, ah\nSo what\'s the problem?\nLet\'s do it quick!\n\nSo take me now, before it\'s too '
'late\nLife\'s too short, so I can\'t wait\nTake me now! Oh, don\'t you see?\nI can\'t get laid in '
'Germany…\n\nGermany! Germany!\n\nYou\'ve got a pussy\nI have a dick, ah\nSo what\'s the '
'problem?\nLet\'s do it quick!\n\nYou\'ve got a pussy\nI have a dick, ah\nSo what\'s the '
'problem?\nLet\'s do it quick!\n\nYou\'ve got a pussy\nI have a dick, ah\nSo what\'s the '
'problem?\nLet\'s do it quick!\n\nSo take me now, before it\'s too late\nLife\'s too short, '
'so I can\'t wait\nTake me now! Oh, don\'t you see?\nI can\'t get laid in Germany…\n '
"in dein Sauerkraut\n\nJust a little bit...\nBe my little bitch!\n\nYou've got a pussy\nI have a "
"dick, ah\nSo what's the problem?\nLet's do it quick!\n\nSo take me now, before it's too "
"late\nLife's too short, so I can't wait\nTake me now! Oh, don't you see?\nI can't get laid in "
"Germany…\n\nGermany! Germany!\n\nYou've got a pussy\nI have a dick, ah\nSo what's the "
"problem?\nLet's do it quick!\n\nYou've got a pussy\nI have a dick, ah\nSo what's the "
"problem?\nLet's do it quick!\n\nYou've got a pussy\nI have a dick, ah\nSo what's the "
"problem?\nLet's do it quick!\n\nSo take me now, before it's too late\nLife's too short, "
"so I can't wait\nTake me now! Oh, don't you see?\nI can't get laid in Germany…\n "
)
has_rights = True
text_language = 'de'

ファイルの表示

@ -35,7 +35,7 @@ class TestMetaData:
'Можете величать меня исчадьем ада\nМожете линчевать меня, мыча как стадо\nНо на мне нет печати зла, '
'сгущать не надо\nКраски. Я счастлив, что я не раб мещанских взглядов\nМожете обличать меня, крича с экрана'
'\nМожете исключать меня из ваших кланов\nНо вы же сами не без греха. Признай, что я был\nК несчастью таким'
' же, как ты. Ша!\nМолчать и на пол!\n\nСпасибо Kaas\'у, так что не смейте обвинять меня в плагиате\nВсе'
" же, как ты. Ша!\nМолчать и на пол!\n\nСпасибо Kaas'у, так что не смейте обвинять меня в плагиате\nВсе"
' сейчас на Одноклассниках, ВКонтакте\nНо далеко не все одноклассники в контакте\nПонимаете, о чем идет'
' речь?\nЙее, Оксимирон. В Лондоне наконец-то солнце'
)

ファイルの表示

@ -8,7 +8,7 @@ class TestMixLink:
text_color = '#6c65a9'
background_color = 'transparent'
background_image_uri = (
'avatars.yandex.net/get-music-misc/28592/mix.5cf0bd5e58ea3a1e70caa07b.' 'background-image.1559281047248/%%'
'avatars.yandex.net/get-music-misc/28592/mix.5cf0bd5e58ea3a1e70caa07b.background-image.1559281047248/%%'
)
cover_white = 'avatars.yandex.net/get-music-misc/28052/mix.5cf0bd5e58ea3a1e70caa07b.cover-white.1559281049219/%%'
cover_uri = 'avatars.yandex.net/get-music-misc/34161/mix.57c6d15a2d3213a86ac653d2.cover.1555818786846/%%'

ファイルの表示

@ -27,7 +27,7 @@ class TestPlaylist:
id_for_from = 'playlist_of_the_day'
dummy_description = 'Слушайте интересные подкасты, чтобы мы могли узнать вас получше и\\xa0собрать этот плейлист'
dummy_page_description = (
'Чтобы собрать для вас этот плейлист, мы должны узнать ' 'вас чуточку поближе. Слушайте больше!'
'Чтобы собрать для вас этот плейлист, мы должны узнать вас чуточку поближе. Слушайте больше!'
)
metrika_id = 666666
coauthors = [1130000003905541]

ファイルの表示

@ -1,5 +1,3 @@
import pytest
from yandex_music import R128

ファイルの表示

@ -2,7 +2,7 @@ from yandex_music import StationData
class TestStationData:
name = 'Marshal\'s station'
name = "Marshal's station"
def test_expected_values(self, station_data):
assert station_data.name == self.name

ファイルの表示

@ -51,7 +51,7 @@ class TestStationTracksResult:
def test_equality(self, id_, sequence):
a = StationTracksResult(id_, sequence, self.batch_id, self.pumpkin)
b = StationTracksResult(id_, sequence, "", False)
b = StationTracksResult(id_, sequence, '', False)
c = StationTracksResult(id_, sequence, self.batch_id, self.pumpkin)
assert a != b

ファイルの表示

@ -1,8 +1,7 @@
import pytest
from tests import TestBest
from yandex_music import Suggestions, Best
from yandex_music import Best, Suggestions
@pytest.fixture(scope='class', params=[1, 2, 3, 4, 5])

ファイルの表示

@ -266,6 +266,7 @@ __all__ = [
'QueueItem',
'Deprecation',
'TrackLyrics',
'LyricsMajor',
'CustomWave',
'R128',
'LyricsInfo',

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -26,7 +26,8 @@ class Account(YandexMusicObject):
passport_phones (:obj:`list` из :obj:`yandex_music.PassportPhone`): Мобильные номера.
registered_at (:obj:`str`, optional): Дата создания учётной записи.
has_info_for_app_metrica (:obj:`bool`, optional): Наличие информации для App Metrica.
child (:obj:`bool`): Дочерний / детский аккаунт (скорее детский, позволяет ограничить доступный контент ребенку на Кинопоиске).
child (:obj:`bool`): Дочерний / детский аккаунт (скорее детский, позволяет ограничить
доступный контент ребенку на Кинопоиске).
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
**kwargs: Произвольные ключевые аргументы полученные от API.
"""

ファイルの表示

@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, AlertButton
from yandex_music import AlertButton, Client
@model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import List, TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import List, TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -102,7 +102,7 @@ class Product(YandexMusicObject):
return None
data = super(Product, cls).de_json(data, client)
from yandex_music import Price, LicenceTextPart
from yandex_music import LicenceTextPart, Price
data['price'] = Price.de_json(data.get('price'), client)
data['intro_price'] = Price.de_json(data.get('intro_price'), client)

ファイルの表示

@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Account, Permissions, Subscription, Plus, StationData, Alert
from yandex_music import Account, Alert, Client, Permissions, Plus, StationData, Subscription
@model
@ -69,7 +69,7 @@ class Status(YandexMusicObject):
return None
data = super(Status, cls).de_json(data, client)
from yandex_music import Account, Permissions, Plus, Subscription, StationData, Alert
from yandex_music import Account, Alert, Permissions, Plus, StationData, Subscription
data['account'] = Account.de_json(data.get('account'), client)
data['permissions'] = Permissions.de_json(data.get('permissions'), client)

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, AutoRenewable, RenewableRemainder, NonAutoRenewable, Operator
from yandex_music import AutoRenewable, Client, NonAutoRenewable, Operator, RenewableRemainder
@model
@ -53,7 +53,7 @@ class Subscription(YandexMusicObject):
return None
data = super(Subscription, cls).de_json(data, client)
from yandex_music import AutoRenewable, RenewableRemainder, NonAutoRenewable, Operator
from yandex_music import AutoRenewable, NonAutoRenewable, Operator, RenewableRemainder
data['auto_renewable'] = AutoRenewable.de_list(data.get('auto_renewable'), client)
data['family_auto_renewable'] = AutoRenewable.de_list(data.get('family_auto_renewable'), client)

ファイルの表示

@ -1,10 +1,10 @@
from typing import Any, TYPE_CHECKING, Optional, List, Union
from typing import TYPE_CHECKING, Any, List, Optional, Union
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Artist, Label, TrackPosition, Track, Deprecation
from yandex_music import Artist, Client, Deprecation, Label, Track, TrackPosition
@model
@ -299,7 +299,7 @@ class Album(YandexMusicObject):
return None
data = super(Album, cls).de_json(data, client)
from yandex_music import Artist, Label, TrackPosition, Track, Deprecation
from yandex_music import Artist, Deprecation, Label, Track, TrackPosition
data['artists'] = Artist.de_list(data.get('artists'), client)

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List, Union
from typing import TYPE_CHECKING, List, Optional, Union
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -58,7 +58,7 @@ class Label(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
labels = list()
labels = []
for label in data:
if isinstance(label, dict):
labels.append(cls.de_json(label, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import Any, TYPE_CHECKING, Optional, List, Union
from typing import TYPE_CHECKING, Any, List, Optional, Union
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Cover, Ratings, Counts, Link, Track, Description, ArtistTracks, ArtistAlbums
from yandex_music import ArtistAlbums, ArtistTracks, Client, Counts, Cover, Description, Link, Ratings, Track
@model
@ -266,7 +266,7 @@ class Artist(YandexMusicObject):
return None
data = super(Artist, cls).de_json(data, client)
from yandex_music import Cover, Ratings, Counts, Link, Track, Description
from yandex_music import Counts, Cover, Description, Link, Ratings, Track
data['cover'] = Cover.de_json(data.get('cover'), client)
data['ratings'] = Ratings.de_json(data.get('ratings'), client)
@ -297,7 +297,7 @@ class Artist(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
artists = list()
artists = []
for artist in data:
artists.append(cls.de_json(artist, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List, Iterator
from typing import TYPE_CHECKING, Iterator, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Album, Pager
from yandex_music import Album, Client, Pager
@model

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List, Iterator
from typing import TYPE_CHECKING, Iterator, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Track, Pager
from yandex_music import Client, Pager, Track
@model
@ -48,7 +48,7 @@ class ArtistTracks(YandexMusicObject):
return None
data = super(ArtistTracks, cls).de_json(data, client)
from yandex_music import Track, Pager
from yandex_music import Pager, Track
data['tracks'] = Track.de_list(data.get('tracks'), client)
data['pager'] = Pager.de_json(data.get('pager'), client)

ファイルの表示

@ -1,10 +1,10 @@
from typing import Any, TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, Any, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Artist, Track, Album, Cover, PlaylistId, Video, Chart, Vinyl, Playlist
from yandex_music import Album, Artist, Chart, Client, Cover, Playlist, PlaylistId, Track, Video, Vinyl
@model
@ -79,7 +79,7 @@ class BriefInfo(YandexMusicObject):
return None
data = super(BriefInfo, cls).de_json(data, client)
from yandex_music import Artist, Track, Album, Cover, PlaylistId, Video, Chart, Vinyl, Playlist
from yandex_music import Album, Artist, Chart, Cover, Playlist, PlaylistId, Track, Video, Vinyl
data['playlists'] = Playlist.de_list(data.get('playlists'), client)
data['artist'] = Artist.de_json(data.get('artist'), client)

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -63,7 +63,7 @@ class Link(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
links = list()
links = []
for link in data:
links.append(cls.de_json(link, client))

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -78,7 +78,7 @@ class Vinyl(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
vinyls = list()
vinyls = []
for vinyl in data:
vinyls.append(cls.de_json(vinyl, client))

ファイルの表示

@ -1,8 +1,8 @@
import dataclasses
import logging
import keyword
import logging
from abc import ABCMeta
from typing import TYPE_CHECKING, Optional, Any
from typing import TYPE_CHECKING, Any, Optional
if TYPE_CHECKING:
from yandex_music import Client
@ -67,8 +67,8 @@ class YandexMusicObject:
fields = {f.name for f in dataclasses.fields(cls)}
cleaned_data = dict()
unknown_data = dict()
cleaned_data = {}
unknown_data = {}
for k, v in data.items():
if k in fields:
@ -110,12 +110,11 @@ class YandexMusicObject:
def parse(val):
if hasattr(val, 'to_dict'):
return val.to_dict(for_request)
elif isinstance(val, list):
if isinstance(val, list):
return [parse(it) for it in val]
elif isinstance(val, dict):
if isinstance(val, dict):
return {key: parse(value) for key, value in val.items()}
else:
return val
return val
data = self.__dict__.copy()
data.pop('client', None)

ファイルの表示

@ -1,7 +1,7 @@
import functools
import logging
from datetime import datetime
from typing import Dict, List, Optional, Union, TypeVar, Callable, Any
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
from yandex_music import (
Album,
@ -9,36 +9,36 @@ from yandex_music import (
ArtistAlbums,
ArtistTracks,
BriefInfo,
ChartInfo,
Dashboard,
DownloadInfo,
Experiments,
Feed,
Genre,
Landing,
LandingList,
Like,
PermissionAlerts,
Playlist,
PlaylistRecommendations,
PromoCodeStatus,
Queue,
QueueItem,
Search,
Settings,
ShotEvent,
Supplement,
SimilarTracks,
StationResult,
StationTracksResult,
Status,
Suggestions,
SimilarTracks,
TrackLyrics,
Supplement,
TagResult,
Track,
TrackLyrics,
TracksList,
UserSettings,
YandexMusicObject,
ChartInfo,
TagResult,
PlaylistRecommendations,
LandingList,
QueueItem,
Queue,
__copyright__,
__license__,
__version__,
@ -855,13 +855,11 @@ class Client(YandexMusicObject):
data = {'kinds': kind}
result = self._request.post(url, data, *args, **kwargs)
return Playlist.de_list(result, self)
else:
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
result = self._request.get(url, *args, **kwargs)
return Playlist.de_json(result, self)
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
result = self._request.get(url, *args, **kwargs)
return Playlist.de_json(result, self)
@log
def users_playlists_recommendations(self, kind: Union[str, int], user_id: Union[str, int] = None, *args, **kwargs):
@ -2196,7 +2194,7 @@ class Client(YandexMusicObject):
action = 'remove' if remove else 'add-multiple'
url = f'{self.base_url}/users/{user_id}/dislikes/tracks/{action}'
result = self._request.post(url, {f'track-ids': ids}, *args, **kwargs)
result = self._request.post(url, {'track-ids': ids}, *args, **kwargs)
return 'revision' in result

ファイルの表示

@ -5,7 +5,7 @@
import functools
import logging
from datetime import datetime
from typing import Dict, List, Optional, Union, TypeVar, Callable, Any
from typing import Any, Callable, Dict, List, Optional, TypeVar, Union
from yandex_music import (
Album,
@ -13,36 +13,36 @@ from yandex_music import (
ArtistAlbums,
ArtistTracks,
BriefInfo,
ChartInfo,
Dashboard,
DownloadInfo,
Experiments,
Feed,
Genre,
Landing,
LandingList,
Like,
PermissionAlerts,
Playlist,
PlaylistRecommendations,
PromoCodeStatus,
Queue,
QueueItem,
Search,
Settings,
ShotEvent,
Supplement,
SimilarTracks,
StationResult,
StationTracksResult,
Status,
Suggestions,
SimilarTracks,
TrackLyrics,
Supplement,
TagResult,
Track,
TrackLyrics,
TracksList,
UserSettings,
YandexMusicObject,
ChartInfo,
TagResult,
PlaylistRecommendations,
LandingList,
QueueItem,
Queue,
__copyright__,
__license__,
__version__,
@ -861,13 +861,11 @@ class ClientAsync(YandexMusicObject):
data = {'kinds': kind}
result = await self._request.post(url, data, *args, **kwargs)
return Playlist.de_list(result, self)
else:
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
result = await self._request.get(url, *args, **kwargs)
return Playlist.de_json(result, self)
url = f'{self.base_url}/users/{user_id}/playlists/{kind}'
result = await self._request.get(url, *args, **kwargs)
return Playlist.de_json(result, self)
@log
async def users_playlists_recommendations(
@ -2214,7 +2212,7 @@ class ClientAsync(YandexMusicObject):
action = 'remove' if remove else 'add-multiple'
url = f'{self.base_url}/users/{user_id}/dislikes/tracks/{action}'
result = await self._request.post(url, {f'track-ids': ids}, *args, **kwargs)
result = await self._request.post(url, {'track-ids': ids}, *args, **kwargs)
return 'revision' in result

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -132,7 +132,7 @@ class Cover(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
covers = list()
covers = []
for cover in data:
covers.append(cls.de_json(cover, client))

ファイルの表示

@ -1,15 +1,15 @@
from typing import TYPE_CHECKING, Optional, List
from hashlib import md5
import xml.dom.minidom as minidom
from hashlib import md5
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client
from xml.dom.minicompat import NodeList
from yandex_music import Client
SIGN_SALT = 'XGRlBW9FXlekgbPrRHuSiA'
@ -40,7 +40,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: 'NodeList') -> str:
def _get_text_node_data(elements: 'NodeList') -> Optional[str]:
""":obj:`str`: Получение текстовой информации из узлов XML элемента."""
for element in elements:
nodes = element.childNodes
@ -48,13 +48,15 @@ class DownloadInfo(YandexMusicObject):
if node.nodeType == node.TEXT_NODE:
return node.data
return None
def __build_direct_link(self, xml: str) -> str:
doc = minidom.parseString(xml)
doc = minidom.parseString(xml) # noqa: S318
host = self._get_text_node_data(doc.getElementsByTagName('host'))
path = self._get_text_node_data(doc.getElementsByTagName('path'))
ts = self._get_text_node_data(doc.getElementsByTagName('ts'))
s = self._get_text_node_data(doc.getElementsByTagName('s'))
sign = md5((SIGN_SALT + path[1::] + s).encode('utf-8')).hexdigest()
sign = md5((SIGN_SALT + path[1::] + s).encode('utf-8')).hexdigest() # noqa: S324
return f'https://{host}/get-mp3/{sign}/{ts}{path}'
@ -165,7 +167,7 @@ class DownloadInfo(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
downloads_info = list()
downloads_info = []
for download_info in data:
downloads_info.append(cls.de_json(download_info, client))
@ -190,7 +192,7 @@ class DownloadInfo(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
downloads_info = list()
downloads_info = []
for download_info in data:
downloads_info.append(cls.de_json(download_info, client))

ファイルの表示

@ -1,6 +1,5 @@
from typing import TYPE_CHECKING, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Album, Track
from yandex_music import Album, Client, Track
@model
@ -60,7 +60,7 @@ class AlbumEvent(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
album_events = list()
album_events = []
for album_event in data:
album_events.append(cls.de_json(album_event, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Artist, Track
from yandex_music import Artist, Client, Track
@model
@ -65,7 +65,7 @@ class ArtistEvent(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
artist_events = list()
artist_events = []
for artist_event in data:
artist_events.append(cls.de_json(artist_event, client))

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -65,7 +65,7 @@ class Day(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
days = list()
days = []
for day in data:
days.append(cls.de_json(day, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Track, AlbumEvent, ArtistEvent
from yandex_music import AlbumEvent, ArtistEvent, Client, Track
@model
@ -67,7 +67,7 @@ class Event(YandexMusicObject):
return None
data = super(Event, cls).de_json(data, client)
from yandex_music import Track, AlbumEvent, ArtistEvent
from yandex_music import AlbumEvent, ArtistEvent, Track
data['tracks'] = Track.de_list(data.get('tracks'), client)
data['albums'] = AlbumEvent.de_list(data.get('albums'), client)
@ -89,7 +89,7 @@ class Event(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
events = list()
events = []
for event in data:
events.append(cls.de_json(event, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, GeneratedPlaylist, Day
from yandex_music import Client, Day, GeneratedPlaylist
@model
@ -54,7 +54,7 @@ class Feed(YandexMusicObject):
return None
data = super(Feed, cls).de_json(data, client)
from yandex_music import GeneratedPlaylist, Day
from yandex_music import Day, GeneratedPlaylist
data['generated_playlists'] = GeneratedPlaylist.de_list(data.get('generated_playlists'), client)
data['days'] = Day.de_list(data.get('days'), client)

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -62,7 +62,7 @@ class TrackWithAds(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
tracks_with_ads = list()
tracks_with_ads = []
for track_with_ads in data:
tracks_with_ads.append(cls.de_json(track_with_ads, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List, Dict
from typing import TYPE_CHECKING, Dict, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Title, Icon, Images
from yandex_music import Client, Icon, Images, Title
@model
@ -63,7 +63,7 @@ class Genre(YandexMusicObject):
return None
data = super(Genre, cls).de_json(data, client)
from yandex_music import Title, Icon, Images
from yandex_music import Icon, Images, Title
data['titles'] = Title.de_dict(data.get('titles'), client)
data['images'] = Images.de_json(data.get('images'), client)

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, Dict
from typing import TYPE_CHECKING, Dict, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -56,7 +56,7 @@ class Title(YandexMusicObject):
if not data:
return {}
titles = dict()
titles = {}
for lang, title in data.items():
titles.update({lang: cls.de_json(title, client)})

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List, Union
from typing import TYPE_CHECKING, List, Optional, Union
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, BlockEntity, PersonalPlaylistsData, PlayContextsData
from yandex_music import BlockEntity, Client, PersonalPlaylistsData, PlayContextsData
@model
@ -56,7 +56,7 @@ class Block(YandexMusicObject):
return None
data = super(Block, cls).de_json(data, client)
from yandex_music import BlockEntity, PlayContextsData, PersonalPlaylistsData
from yandex_music import BlockEntity, PersonalPlaylistsData, PlayContextsData
data['entities'] = BlockEntity.de_list(data.get('entities'), client)
@ -82,7 +82,7 @@ class Block(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
blocks = list()
blocks = []
for block in data:
blocks.append(cls.de_json(block, client))

ファイルの表示

@ -1,14 +1,14 @@
from typing import TYPE_CHECKING, Optional, List, Union
from typing import TYPE_CHECKING, List, Optional, Union
from yandex_music import (
YandexMusicObject,
Promotion,
Album,
Playlist,
MixLink,
PlayContext,
ChartItem,
GeneratedPlaylist,
MixLink,
PlayContext,
Playlist,
Promotion,
YandexMusicObject,
)
from yandex_music.utils import model
@ -86,7 +86,7 @@ class BlockEntity(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
entities = list()
entities = []
for entity in data:
entities.append(cls.de_json(entity, client))

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,6 +1,6 @@
from typing import TYPE_CHECKING, Optional
from yandex_music import YandexMusicObject, Playlist, ChartInfoMenu
from yandex_music import ChartInfoMenu, Playlist, YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:

ファイルの表示

@ -1,6 +1,6 @@
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject, ChartInfoMenuItem
from yandex_music import ChartInfoMenuItem, YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Track, Chart
from yandex_music import Chart, Client, Track
@model
@ -60,7 +60,7 @@ class ChartItem(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
tracks = list()
tracks = []
for track in data:
tracks.append(cls.de_json(track, client))

ファイルの表示

@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Optional, List, Union
from typing import TYPE_CHECKING, List, Optional, Union
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Block
from yandex_music import Block, Client
@model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -40,7 +40,7 @@ class LandingList(YandexMusicObject):
self._id_attrs = (self.id, self.new_releases, self.new_playlists, self.podcasts)
@classmethod
def de_json(cls, data: dict, client: 'Client') -> Optional['Chart']:
def de_json(cls, data: dict, client: 'Client') -> Optional['LandingList']:
"""Десериализация объекта.
Args:

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.exceptions import YandexMusicError
@ -71,7 +71,7 @@ class MixLink(YandexMusicObject):
"""
if not self.cover_white:
raise YandexMusicError('You can\'t get cover white because it\'s None.')
raise YandexMusicError("You can't get cover white because it's None.")
return f'https://{self.cover_white.replace("%%", size)}'
@ -238,7 +238,7 @@ class MixLink(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
mix_links = list()
mix_links = []
for mix_link in data:
mix_links.append(cls.de_json(mix_link, client))

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -136,7 +136,7 @@ class Promotion(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
promotions = list()
promotions = []
for promotion in data:
promotions.append(cls.de_json(promotion, client))

ファイルの表示

@ -1,9 +1,8 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, Track

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -64,7 +64,7 @@ class TrackShortOld(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
tracks = list()
tracks = []
for track in data:
tracks.append(cls.de_json(track, client))

ファイルの表示

@ -1,4 +1,4 @@
from typing import List, Optional, TYPE_CHECKING
from typing import TYPE_CHECKING, List, Optional
from yandex_music import Album, Artist, Playlist, YandexMusicObject
from yandex_music.utils import model
@ -95,7 +95,7 @@ class Like(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
likes = list()
likes = []
for like in data:
likes.append(cls.de_json(like, client, type_))

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import Any, TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, User, CaseForms
from yandex_music import CaseForms, Client, User
@model
@ -39,7 +39,7 @@ class MadeFor(YandexMusicObject):
return None
data = super(MadeFor, cls).de_json(data, client)
from yandex_music import User, CaseForms
from yandex_music import CaseForms, User
data['user_info'] = User.de_json(data.get('user_info'), client)
data['case_forms'] = CaseForms.de_json(data.get('case_forms'), client)

ファイルの表示

@ -1,25 +1,25 @@
from typing import Any, TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, Any, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import (
Client,
User,
Cover,
MadeFor,
TrackShort,
PlaylistAbsence,
PlayCounter,
PlaylistRecommendations,
Artist,
TrackId,
Contest,
OpenGraphData,
Brand,
Pager,
Client,
Contest,
Cover,
CustomWave,
MadeFor,
OpenGraphData,
Pager,
PlayCounter,
PlaylistAbsence,
PlaylistRecommendations,
TrackId,
TrackShort,
User,
)
@ -353,24 +353,24 @@ class Playlist(YandexMusicObject):
"""
return (await self.client.users_playlists(self.kind, self.owner.uid, *args, **kwargs)).tracks
def insert_track(self, track_id: int, album_id: int, *args, **kwargs) -> Optional['Playlist']:
def insert_track(self, track_id: int, album_id: int, **kwargs) -> Optional['Playlist']:
"""Сокращение для::
client.users_playlists_insert_track(self.kind, track_id, album_id, user_id=self.owner.uid,
revision=self.revision, *args, **kwargs)
"""
return self.client.users_playlists_insert_track(
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, *args, **kwargs
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, **kwargs
)
async def insert_track_async(self, track_id: int, album_id: int, *args, **kwargs) -> Optional['Playlist']:
async def insert_track_async(self, track_id: int, album_id: int, **kwargs) -> Optional['Playlist']:
"""Сокращение для::
await client.users_playlists_insert_track(self.kind, track_id, album_id, user_id=self.owner.uid,
revision=self.revision, *args, **kwargs)
"""
return await self.client.users_playlists_insert_track(
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, *args, **kwargs
self.kind, track_id, album_id, user_id=self.owner.uid, revision=self.revision, **kwargs
)
def delete_tracks(self, from_: int, to: int, *args, **kwargs) -> Optional['Playlist']:
@ -421,19 +421,19 @@ class Playlist(YandexMusicObject):
data = super(Playlist, cls).de_json(data, client)
from yandex_music import (
User,
MadeFor,
Cover,
PlayCounter,
TrackShort,
PlaylistAbsence,
Artist,
TrackId,
Contest,
OpenGraphData,
Brand,
Contest,
Cover,
CustomWave,
MadeFor,
OpenGraphData,
Pager,
PlayCounter,
PlaylistAbsence,
TrackId,
TrackShort,
User,
)
data['owner'] = User.de_json(data.get('owner'), client)

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -74,7 +74,7 @@ class PlaylistId(YandexMusicObject):
if not cls.is_valid_model_data(data, array=True):
return []
playlist_ids = list()
playlist_ids = []
for playlist_id in data:
playlist_ids.append(cls.de_json(playlist_id, client))

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
@ -39,7 +39,7 @@ class TagResult(YandexMusicObject):
return None
data = super(TagResult, cls).de_json(data, client)
from yandex_music import Tag, PlaylistId
from yandex_music import PlaylistId, Tag
data['tag'] = Tag.de_json(data.get('tag'), client)
data['ids'] = PlaylistId.de_list(data.get('ids'), client)

ファイルの表示

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Optional, List
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model

ファイルの表示

@ -1,10 +1,10 @@
from typing import List, TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, List, Optional
from yandex_music import YandexMusicObject
from yandex_music.utils import model
if TYPE_CHECKING:
from yandex_music import Client, TrackId, Context
from yandex_music import Client, Context, TrackId
@model
@ -50,7 +50,7 @@ class Queue(YandexMusicObject):
if not cls.is_valid_model_data(data):
return None
from yandex_music import TrackId, Context
from yandex_music import Context, TrackId
data = super(Queue, cls).de_json(data, client)
data['tracks'] = TrackId.de_list(data.get('tracks'), client)

変更されたファイルが多すぎるため、一部のファイルは表示されません さらに表示