deezer-python 6.1.0__tar.gz → 6.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {deezer_python-6.1.0 → deezer_python-6.2.0}/PKG-INFO +2 -2
- {deezer_python-6.1.0 → deezer_python-6.2.0}/README.md +1 -1
- {deezer_python-6.1.0 → deezer_python-6.2.0}/pyproject.toml +63 -14
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/__init__.py +1 -1
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/client.py +53 -25
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/dates.py +2 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/exceptions.py +8 -6
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/pagination.py +9 -6
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/chart.py +15 -5
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/episode.py +1 -1
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/podcast.py +1 -1
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/resource.py +3 -1
- {deezer_python-6.1.0 → deezer_python-6.2.0}/LICENSE.txt +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/__init__.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/album.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/artist.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/editorial.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/genre.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/playlist.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/radio.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/track.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/resources/user.py +0 -0
- {deezer_python-6.1.0 → deezer_python-6.2.0}/src/deezer/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: deezer-python
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.2.0
|
|
4
4
|
Summary: A friendly wrapper library for the Deezer API
|
|
5
5
|
Home-page: https://github.com/browniebroke/deezer-python
|
|
6
6
|
License: MIT
|
|
@@ -89,7 +89,7 @@ The package is published on
|
|
|
89
89
|
Easily query the Deezer API from you Python code. The data returned by the Deezer
|
|
90
90
|
API is mapped to python resources:
|
|
91
91
|
|
|
92
|
-
```
|
|
92
|
+
```pycon
|
|
93
93
|
>>> client = deezer.Client()
|
|
94
94
|
>>> client.get_album(680407).title
|
|
95
95
|
'Monkey Business'
|
|
@@ -58,7 +58,7 @@ The package is published on
|
|
|
58
58
|
Easily query the Deezer API from you Python code. The data returned by the Deezer
|
|
59
59
|
API is mapped to python resources:
|
|
60
60
|
|
|
61
|
-
```
|
|
61
|
+
```pycon
|
|
62
62
|
>>> client = deezer.Client()
|
|
63
63
|
>>> client.get_album(680407).title
|
|
64
64
|
'Monkey Business'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "deezer-python"
|
|
3
|
-
version = "6.
|
|
3
|
+
version = "6.2.0"
|
|
4
4
|
description = "A friendly wrapper library for the Deezer API"
|
|
5
5
|
authors = ["Bruno Alla <alla.brunoo@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -34,25 +34,26 @@ requests = ">=2.18"
|
|
|
34
34
|
optional = true
|
|
35
35
|
|
|
36
36
|
[tool.poetry.group.docs.dependencies]
|
|
37
|
-
myst-parser = ">=0.16"
|
|
38
|
-
sphinx = ">=4.0"
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
myst-parser = { version = ">=0.16", python = ">=3.11" }
|
|
38
|
+
sphinx = { version = ">=4.0", python = ">=3.11" }
|
|
39
|
+
furo = { version = ">=2023.5.20", python = ">=3.11" }
|
|
40
|
+
sphinx-autobuild = { version = ">=2024.0.0", python = ">=3.11" }
|
|
41
41
|
|
|
42
42
|
[tool.poetry.group.dev.dependencies]
|
|
43
43
|
coverage = "^7.0"
|
|
44
|
-
environs = "^
|
|
45
|
-
pytest = "^
|
|
46
|
-
pytest-cov = "^
|
|
44
|
+
environs = "^11.0.0"
|
|
45
|
+
pytest = "^8.0.0"
|
|
46
|
+
pytest-cov = "^5.0.0"
|
|
47
47
|
pytest-mock = "^3.6"
|
|
48
48
|
pytest-vcr = "^1.0"
|
|
49
|
-
vcrpy = "^
|
|
49
|
+
vcrpy = "^6.0.0"
|
|
50
50
|
deezer-oauth-cli = "^1.0.0"
|
|
51
51
|
|
|
52
52
|
[tool.semantic_release]
|
|
53
53
|
version_toml = ["pyproject.toml:tool.poetry.version"]
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
version_variables = [
|
|
55
|
+
"src/deezer/__init__.py:__version__",
|
|
56
|
+
]
|
|
56
57
|
build_command = "pip install poetry && poetry build"
|
|
57
58
|
|
|
58
59
|
[tool.semantic_release.changelog]
|
|
@@ -64,6 +65,16 @@ exclude_commit_patterns = [
|
|
|
64
65
|
[tool.semantic_release.changelog.environment]
|
|
65
66
|
keep_trailing_newline = true
|
|
66
67
|
|
|
68
|
+
[tool.semantic_release.branches.main]
|
|
69
|
+
match = "main"
|
|
70
|
+
|
|
71
|
+
[tool.semantic_release.branches.stable]
|
|
72
|
+
match = "(?!stable/*$)"
|
|
73
|
+
|
|
74
|
+
[tool.semantic_release.branches.noop]
|
|
75
|
+
match = "(?!main$)"
|
|
76
|
+
prerelease = true
|
|
77
|
+
|
|
67
78
|
[tool.pytest.ini_options]
|
|
68
79
|
addopts = "-v -Wdefault --cov=deezer"
|
|
69
80
|
pythonpath = ["src"]
|
|
@@ -81,9 +92,47 @@ exclude_lines = [
|
|
|
81
92
|
"raise NotImplementedError",
|
|
82
93
|
]
|
|
83
94
|
|
|
84
|
-
[tool.
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
[tool.ruff]
|
|
96
|
+
target-version = "py38"
|
|
97
|
+
line-length = 120
|
|
98
|
+
|
|
99
|
+
[tool.ruff.lint]
|
|
100
|
+
ignore = [
|
|
101
|
+
"D203", # 1 blank line required before class docstring
|
|
102
|
+
"D212", # Multi-line docstring summary should start at the first line
|
|
103
|
+
"D100", # Missing docstring in public module
|
|
104
|
+
"D104", # Missing docstring in public package
|
|
105
|
+
"D107", # Missing docstring in `__init__`
|
|
106
|
+
"D401", # First line of docstring should be in imperative mood
|
|
107
|
+
]
|
|
108
|
+
select = [
|
|
109
|
+
"B", # flake8-bugbear
|
|
110
|
+
"D", # flake8-docstrings
|
|
111
|
+
"C4", # flake8-comprehensions
|
|
112
|
+
"S", # flake8-bandit
|
|
113
|
+
"F", # pyflake
|
|
114
|
+
"E", # pycodestyle
|
|
115
|
+
"W", # pycodestyle
|
|
116
|
+
"UP", # pyupgrade
|
|
117
|
+
"I", # isort
|
|
118
|
+
"RUF", # ruff specific
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
[tool.ruff.lint.per-file-ignores]
|
|
122
|
+
"tests/**/*" = [
|
|
123
|
+
"D100",
|
|
124
|
+
"D101",
|
|
125
|
+
"D102",
|
|
126
|
+
"D103",
|
|
127
|
+
"D104",
|
|
128
|
+
"S101",
|
|
129
|
+
]
|
|
130
|
+
"setup.py" = ["D100"]
|
|
131
|
+
"conftest.py" = ["D100"]
|
|
132
|
+
"docs/conf.py" = ["D100"]
|
|
133
|
+
|
|
134
|
+
[tool.ruff.lint.isort]
|
|
135
|
+
known-first-party = ["deezer"]
|
|
87
136
|
|
|
88
137
|
[tool.mypy]
|
|
89
138
|
# suppress errors about unsatisfied imports
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import warnings
|
|
4
|
+
from typing import Any, ClassVar
|
|
4
5
|
|
|
5
6
|
import requests
|
|
6
7
|
|
|
@@ -25,6 +26,8 @@ from deezer.resources import (
|
|
|
25
26
|
User,
|
|
26
27
|
)
|
|
27
28
|
|
|
29
|
+
_UNSET = object()
|
|
30
|
+
|
|
28
31
|
|
|
29
32
|
class Client:
|
|
30
33
|
"""
|
|
@@ -34,10 +37,10 @@ class Client:
|
|
|
34
37
|
be passed in to the constructor as kwargs.
|
|
35
38
|
|
|
36
39
|
>>> import deezer
|
|
37
|
-
>>> client = deezer.Client(
|
|
40
|
+
>>> client = deezer.Client()
|
|
38
41
|
|
|
39
|
-
This client provides several
|
|
40
|
-
|
|
42
|
+
This client provides several methods to retrieve the content most
|
|
43
|
+
kinds of Deezer objects, based on their json structure.
|
|
41
44
|
|
|
42
45
|
Headers can be forced by using the ``headers`` kwarg.
|
|
43
46
|
For example, use ``Accept-Language`` header to force the output language.
|
|
@@ -45,13 +48,20 @@ class Client:
|
|
|
45
48
|
>>> import deezer
|
|
46
49
|
>>> client = deezer.Client(headers={'Accept-Language': 'fr'})
|
|
47
50
|
|
|
48
|
-
:param app_id: application ID.
|
|
49
|
-
:param app_secret: application secret.
|
|
50
51
|
:param access_token: user access token.
|
|
51
52
|
:param headers: a dictionary of headers to be used.
|
|
53
|
+
|
|
54
|
+
.. deprecated:: 6.2.0
|
|
55
|
+
|
|
56
|
+
The following parameters will be removed in the next major version:
|
|
57
|
+
|
|
58
|
+
* **app_id**
|
|
59
|
+
* **app_secret**
|
|
60
|
+
|
|
61
|
+
They were never actively used by the package.
|
|
52
62
|
"""
|
|
53
63
|
|
|
54
|
-
objects_types = {
|
|
64
|
+
objects_types: ClassVar[dict[str, type[Resource] | None]] = {
|
|
55
65
|
"album": Album,
|
|
56
66
|
"artist": Artist,
|
|
57
67
|
"chart": Chart,
|
|
@@ -69,10 +79,29 @@ class Client:
|
|
|
69
79
|
base_url = "https://api.deezer.com"
|
|
70
80
|
|
|
71
81
|
def __init__(
|
|
72
|
-
self,
|
|
82
|
+
self,
|
|
83
|
+
app_id=_UNSET,
|
|
84
|
+
app_secret=_UNSET,
|
|
85
|
+
access_token=None,
|
|
86
|
+
headers=None,
|
|
87
|
+
**kwargs,
|
|
73
88
|
):
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
if app_id is not _UNSET:
|
|
90
|
+
warnings.warn(
|
|
91
|
+
"The 'app_id' parameter is not actually used and is deprecated. "
|
|
92
|
+
"It will be removed in the next major release.",
|
|
93
|
+
DeprecationWarning,
|
|
94
|
+
stacklevel=2,
|
|
95
|
+
)
|
|
96
|
+
self.app_id = app_id
|
|
97
|
+
if app_secret is not _UNSET:
|
|
98
|
+
warnings.warn(
|
|
99
|
+
"The 'app_secret' parameter is not actually used and is deprecated. "
|
|
100
|
+
"It will be removed in the next major release.",
|
|
101
|
+
DeprecationWarning,
|
|
102
|
+
stacklevel=2,
|
|
103
|
+
)
|
|
104
|
+
self.app_secret = app_secret
|
|
76
105
|
self.access_token = access_token
|
|
77
106
|
self.session = requests.Session()
|
|
78
107
|
|
|
@@ -88,8 +117,7 @@ class Client:
|
|
|
88
117
|
paginate_list=False,
|
|
89
118
|
):
|
|
90
119
|
"""
|
|
91
|
-
Recursively convert dictionary
|
|
92
|
-
to :class:`~deezer.Resource` object
|
|
120
|
+
Recursively convert dictionary to :class:`~deezer.Resource` object.
|
|
93
121
|
|
|
94
122
|
:param item: the JSON response as dict.
|
|
95
123
|
:param parent: A reference to the parent resource, to avoid fetching again.
|
|
@@ -129,7 +157,7 @@ class Client:
|
|
|
129
157
|
return True
|
|
130
158
|
else:
|
|
131
159
|
raise DeezerUnknownResource(f"Unable to find resource type for {result!r}")
|
|
132
|
-
assert object_class is not None #
|
|
160
|
+
assert object_class is not None # noqa S101
|
|
133
161
|
return object_class(self, result)
|
|
134
162
|
|
|
135
163
|
def request(
|
|
@@ -167,7 +195,7 @@ class Client:
|
|
|
167
195
|
json_data = response.json()
|
|
168
196
|
if not isinstance(json_data, dict):
|
|
169
197
|
return json_data
|
|
170
|
-
if
|
|
198
|
+
if json_data.get("error"):
|
|
171
199
|
raise DeezerErrorResponse(json_data)
|
|
172
200
|
return self._process_json(
|
|
173
201
|
json_data,
|
|
@@ -281,7 +309,7 @@ class Client:
|
|
|
281
309
|
|
|
282
310
|
def get_genre(self, genre_id: int) -> Genre:
|
|
283
311
|
"""
|
|
284
|
-
Get the genre with the given ID
|
|
312
|
+
Get the genre with the given ID.
|
|
285
313
|
|
|
286
314
|
:returns: a :class:`~deezer.Genre` object
|
|
287
315
|
"""
|
|
@@ -419,7 +447,7 @@ class Client:
|
|
|
419
447
|
|
|
420
448
|
def add_user_album(self, album_id: int) -> bool:
|
|
421
449
|
"""
|
|
422
|
-
Add an album to the user's library
|
|
450
|
+
Add an album to the user's library.
|
|
423
451
|
|
|
424
452
|
:param album_id: the ID of the album to add.
|
|
425
453
|
:return: boolean whether the operation succeeded.
|
|
@@ -428,7 +456,7 @@ class Client:
|
|
|
428
456
|
|
|
429
457
|
def remove_user_album(self, album_id: int) -> bool:
|
|
430
458
|
"""
|
|
431
|
-
Remove an album from the user's library
|
|
459
|
+
Remove an album from the user's library.
|
|
432
460
|
|
|
433
461
|
:param album_id: the ID of the album to remove.
|
|
434
462
|
:return: boolean whether the operation succeeded.
|
|
@@ -448,7 +476,7 @@ class Client:
|
|
|
448
476
|
|
|
449
477
|
def add_user_artist(self, artist_id: int) -> bool:
|
|
450
478
|
"""
|
|
451
|
-
Add an artist to the user's library
|
|
479
|
+
Add an artist to the user's library.
|
|
452
480
|
|
|
453
481
|
:param artist_id: the ID of the artist to add.
|
|
454
482
|
:return: boolean whether the operation succeeded.
|
|
@@ -457,7 +485,7 @@ class Client:
|
|
|
457
485
|
|
|
458
486
|
def remove_user_artist(self, artist_id: int) -> bool:
|
|
459
487
|
"""
|
|
460
|
-
Remove an artist from the user's library
|
|
488
|
+
Remove an artist from the user's library.
|
|
461
489
|
|
|
462
490
|
:param artist_id: the ID of the artist to remove.
|
|
463
491
|
:return: boolean whether the operation succeeded.
|
|
@@ -526,7 +554,7 @@ class Client:
|
|
|
526
554
|
|
|
527
555
|
def add_user_track(self, track_id: int) -> bool:
|
|
528
556
|
"""
|
|
529
|
-
Add a track to the user's library
|
|
557
|
+
Add a track to the user's library.
|
|
530
558
|
|
|
531
559
|
:param track_id: the ID of the track to add.
|
|
532
560
|
:return: boolean whether the operation succeeded.
|
|
@@ -535,7 +563,7 @@ class Client:
|
|
|
535
563
|
|
|
536
564
|
def remove_user_track(self, track_id: int) -> bool:
|
|
537
565
|
"""
|
|
538
|
-
Remove a track from the user's library
|
|
566
|
+
Remove a track from the user's library.
|
|
539
567
|
|
|
540
568
|
:param track_id: the ID of the track to remove.
|
|
541
569
|
:return: boolean whether the operation succeeded.
|
|
@@ -544,7 +572,7 @@ class Client:
|
|
|
544
572
|
|
|
545
573
|
def remove_user_playlist(self, playlist_id: int) -> bool:
|
|
546
574
|
"""
|
|
547
|
-
Remove a playlist from the user's library
|
|
575
|
+
Remove a playlist from the user's library.
|
|
548
576
|
|
|
549
577
|
:param playlist_id: the ID of the playlist to remove.
|
|
550
578
|
:return: boolean whether the operation succeeded.
|
|
@@ -553,7 +581,7 @@ class Client:
|
|
|
553
581
|
|
|
554
582
|
def add_user_playlist(self, playlist_id: int) -> bool:
|
|
555
583
|
"""
|
|
556
|
-
Add a playlist to the user's library
|
|
584
|
+
Add a playlist to the user's library.
|
|
557
585
|
|
|
558
586
|
:param playlist_id: the ID of the playlist to add.
|
|
559
587
|
:return: boolean whether the operation succeeded.
|
|
@@ -562,7 +590,7 @@ class Client:
|
|
|
562
590
|
|
|
563
591
|
def create_playlist(self, playlist_name) -> int:
|
|
564
592
|
"""
|
|
565
|
-
Create a playlist on the user's account
|
|
593
|
+
Create a playlist on the user's account.
|
|
566
594
|
|
|
567
595
|
:param playlist_name: the name of the playlist.
|
|
568
596
|
:return: the ID of the playlist that was created
|
|
@@ -574,7 +602,7 @@ class Client:
|
|
|
574
602
|
|
|
575
603
|
def delete_playlist(self, playlist_id) -> bool:
|
|
576
604
|
"""
|
|
577
|
-
Delete a playlist from the user's account
|
|
605
|
+
Delete a playlist from the user's account.
|
|
578
606
|
|
|
579
607
|
:param playlist_id: the ID of the playlist to remove.
|
|
580
608
|
:return: boolean whether the operation succeeded.
|
|
@@ -7,6 +7,7 @@ DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def parse_date(date_str: str) -> dt.date | None:
|
|
10
|
+
"""Parse a date from a string to a date object."""
|
|
10
11
|
datetime = parse_datetime(date_str, DATE_FORMAT)
|
|
11
12
|
return datetime.date() if datetime else None
|
|
12
13
|
|
|
@@ -15,6 +16,7 @@ def parse_datetime(
|
|
|
15
16
|
datetime_str: str,
|
|
16
17
|
date_format: str = DATETIME_FORMAT,
|
|
17
18
|
) -> dt.datetime | None:
|
|
19
|
+
"""Parse a datetime from a string to a datetime object."""
|
|
18
20
|
if not datetime_str or datetime_str.startswith("0000-00-00"):
|
|
19
21
|
return None
|
|
20
22
|
return dt.datetime.strptime(datetime_str, date_format)
|
|
@@ -25,12 +25,14 @@ class DeezerHTTPError(DeezerAPIException):
|
|
|
25
25
|
|
|
26
26
|
@classmethod
|
|
27
27
|
def from_http_error(cls, exc: requests.HTTPError) -> DeezerHTTPError:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
"""Initialise the appropriate internal exception from a HTTPError."""
|
|
29
|
+
if exc.response is not None:
|
|
30
|
+
if exc.response.status_code in {502, 503, 504}:
|
|
31
|
+
return DeezerRetryableHTTPError(exc)
|
|
32
|
+
if exc.response.status_code == 403:
|
|
33
|
+
return DeezerForbiddenError(exc)
|
|
34
|
+
if exc.response.status_code == 404:
|
|
35
|
+
return DeezerNotFoundError(exc)
|
|
34
36
|
return DeezerHTTPError(exc)
|
|
35
37
|
|
|
36
38
|
|
|
@@ -33,6 +33,7 @@ class PaginatedList(Generic[ResourceType]):
|
|
|
33
33
|
self.__iter = iter(self)
|
|
34
34
|
|
|
35
35
|
def __repr__(self) -> str:
|
|
36
|
+
"""Convenient representation giving a preview of the content."""
|
|
36
37
|
repr_size = 5
|
|
37
38
|
data: list[ResourceType | str] = list(self[: repr_size + 1])
|
|
38
39
|
if len(data) > repr_size:
|
|
@@ -40,17 +41,16 @@ class PaginatedList(Generic[ResourceType]):
|
|
|
40
41
|
return f"<{self.__class__.__name__} {data!r}>"
|
|
41
42
|
|
|
42
43
|
@overload
|
|
43
|
-
def __getitem__(self, index: int) -> ResourceType:
|
|
44
|
-
...
|
|
44
|
+
def __getitem__(self, index: int) -> ResourceType: ...
|
|
45
45
|
|
|
46
46
|
@overload
|
|
47
|
-
def __getitem__(self, index: slice) -> list[ResourceType]:
|
|
48
|
-
...
|
|
47
|
+
def __getitem__(self, index: slice) -> list[ResourceType]: ...
|
|
49
48
|
|
|
50
49
|
def __getitem__(
|
|
51
50
|
self,
|
|
52
51
|
index: int | slice,
|
|
53
52
|
) -> ResourceType | list[ResourceType]:
|
|
53
|
+
"""Get an item or a slice of items from the list."""
|
|
54
54
|
if isinstance(index, int):
|
|
55
55
|
self._fetch_to_index(index)
|
|
56
56
|
return self.__elements[index]
|
|
@@ -62,14 +62,17 @@ class PaginatedList(Generic[ResourceType]):
|
|
|
62
62
|
return self.__elements[index]
|
|
63
63
|
|
|
64
64
|
def __iter__(self) -> Generator[ResourceType, None, None]:
|
|
65
|
+
"""Iterate over the internal, fetching new pages as needed."""
|
|
65
66
|
yield from self.__elements
|
|
66
67
|
while self._could_grow():
|
|
67
68
|
yield from self._grow()
|
|
68
69
|
|
|
69
70
|
def __next__(self) -> ResourceType:
|
|
71
|
+
"""Get the next item from the list."""
|
|
70
72
|
return next(self.__iter)
|
|
71
73
|
|
|
72
74
|
def __len__(self) -> int:
|
|
75
|
+
"""Get the total number of items across all pages."""
|
|
73
76
|
return self.total
|
|
74
77
|
|
|
75
78
|
def _could_grow(self) -> bool:
|
|
@@ -81,7 +84,7 @@ class PaginatedList(Generic[ResourceType]):
|
|
|
81
84
|
return new_elements
|
|
82
85
|
|
|
83
86
|
def _fetch_next_page(self) -> list[ResourceType]:
|
|
84
|
-
assert self.__next_path is not None #
|
|
87
|
+
assert self.__next_path is not None # noqa S101
|
|
85
88
|
response_payload = self.__client.request(
|
|
86
89
|
"GET",
|
|
87
90
|
self.__next_path,
|
|
@@ -116,5 +119,5 @@ class PaginatedList(Generic[ResourceType]):
|
|
|
116
119
|
**params,
|
|
117
120
|
)
|
|
118
121
|
self.__total = response_payload["total"]
|
|
119
|
-
assert self.__total is not None #
|
|
122
|
+
assert self.__total is not None # noqa S101
|
|
120
123
|
return self.__total
|
|
@@ -32,35 +32,45 @@ class Chart(Resource):
|
|
|
32
32
|
|
|
33
33
|
def get_tracks(self, **kwargs) -> PaginatedList[Track]:
|
|
34
34
|
"""
|
|
35
|
+
Return the chart for tracks.
|
|
36
|
+
|
|
35
37
|
:returns: a :class:`PaginatedList <deezer.PaginatedList>`
|
|
36
|
-
|
|
38
|
+
of :class:`Track <deezer.Track>` instances
|
|
37
39
|
"""
|
|
38
40
|
return self.get_paginated_list("tracks", **kwargs)
|
|
39
41
|
|
|
40
42
|
def get_albums(self, **kwargs) -> PaginatedList[Album]:
|
|
41
43
|
"""
|
|
44
|
+
Return the chart for albums.
|
|
45
|
+
|
|
42
46
|
:returns: a :class:`PaginatedList <deezer.PaginatedList>`
|
|
43
|
-
|
|
47
|
+
of :class:`Album <deezer.Album>` instances
|
|
44
48
|
"""
|
|
45
49
|
return self.get_paginated_list("albums", **kwargs)
|
|
46
50
|
|
|
47
51
|
def get_artists(self, **kwargs) -> PaginatedList[Artist]:
|
|
48
52
|
"""
|
|
53
|
+
Return the chart for artists.
|
|
54
|
+
|
|
49
55
|
:returns: a :class:`PaginatedList <deezer.PaginatedList>`
|
|
50
|
-
|
|
56
|
+
of :class:`Artist <deezer.Artist>` instances
|
|
51
57
|
"""
|
|
52
58
|
return self.get_paginated_list("artists", **kwargs)
|
|
53
59
|
|
|
54
60
|
def get_playlists(self, **kwargs) -> PaginatedList[Playlist]:
|
|
55
61
|
"""
|
|
62
|
+
Return the chart for playlists.
|
|
63
|
+
|
|
56
64
|
:returns: a :class:`PaginatedList <deezer.PaginatedList>`
|
|
57
|
-
|
|
65
|
+
of :class:`Playlist <deezer.Playlist>` instances
|
|
58
66
|
"""
|
|
59
67
|
return self.get_paginated_list("playlists", **kwargs)
|
|
60
68
|
|
|
61
69
|
def get_podcasts(self, **kwargs) -> PaginatedList[Podcast]:
|
|
62
70
|
"""
|
|
71
|
+
Return the chart for podcasts.
|
|
72
|
+
|
|
63
73
|
:returns: a :class:`PaginatedList <deezer.PaginatedList>`
|
|
64
|
-
|
|
74
|
+
of :class:`Podcast <deezer.Podcast>` instances
|
|
65
75
|
"""
|
|
66
76
|
return self.get_paginated_list("podcasts", **kwargs)
|
|
@@ -32,7 +32,7 @@ class Podcast(Resource):
|
|
|
32
32
|
|
|
33
33
|
def get_episodes(self, **kwargs) -> PaginatedList[Episode]:
|
|
34
34
|
"""
|
|
35
|
-
Get episodes from a podcast
|
|
35
|
+
Get episodes from a podcast.
|
|
36
36
|
|
|
37
37
|
:returns: a :class:`PaginatedList <deezer.PaginatedList>`
|
|
38
38
|
of :class:`Episode <deezer.Episode>` instances
|
|
@@ -34,6 +34,7 @@ class Resource:
|
|
|
34
34
|
setattr(self, key, json[key])
|
|
35
35
|
|
|
36
36
|
def __repr__(self):
|
|
37
|
+
"""Convenient representation giving a preview of the item."""
|
|
37
38
|
name = getattr(self, "name", None)
|
|
38
39
|
title = getattr(self, "title", None)
|
|
39
40
|
id_ = getattr(self, "id", None)
|
|
@@ -101,7 +102,8 @@ class Resource:
|
|
|
101
102
|
self,
|
|
102
103
|
relation: str,
|
|
103
104
|
**kwargs,
|
|
104
|
-
):
|
|
105
|
+
) -> PaginatedList:
|
|
106
|
+
"""Build the pagination object based on the relation."""
|
|
105
107
|
return PaginatedList(
|
|
106
108
|
client=self.client,
|
|
107
109
|
base_path=f"{self.type}/{self.id}/{relation}",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|