Pagination helpers.
List endpoints answer with an envelope like::
{"data": [...], "total": 123, "prev": "...", "next": "..."}
:class:PaginatedList is a small immutable view over that envelope: list()
gives the items, .total the advertised total, and :meth:iter_all_pages
walks next links until exhaustion.
PaginatedList
Bases: Generic[T]
A single page of a Deezer collection plus navigation helpers.
Source code in deezify/paginator.py
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 | class PaginatedList(Generic[T]):
"""A single page of a Deezer collection plus navigation helpers."""
def __init__(
self,
payload: dict[str, Any] | list[Any],
*,
fetch: Callable[[str], dict[str, Any]] | None = None,
) -> None:
if isinstance(payload, list):
payload = {"data": payload, "total": len(payload)}
self._payload = payload
self._fetch = fetch
# -- page content ----------------------------------------------------
@property
def data(self) -> list[T]:
items = self._payload.get("data", [])
return list(items) if isinstance(items, list) else []
@property
def total(self) -> int | None:
total = self._payload.get("total")
return int(total) if isinstance(total, (int, float)) else None
@property
def next_url(self) -> str | None:
nxt = self._payload.get("next")
return str(nxt) if nxt else None
@property
def prev_url(self) -> str | None:
prev = self._payload.get("prev")
return str(prev) if prev else None
@property
def checksum(self) -> str | None:
checksum = self._payload.get("checksum")
return str(checksum) if checksum else None
@property
def raw(self) -> dict[str, Any]:
return self._payload
# -- dunder sugar ----------------------------------------------------
def __iter__(self) -> Iterator[T]:
return iter(self.data)
def __len__(self) -> int:
return len(self.data)
def __getitem__(self, index: int) -> T:
return self.data[index]
def __repr__(self) -> str: # pragma: no cover - cosmetic
return f"PaginatedList(data={len(self)}, total={self.total})"
# -- navigation ------------------------------------------------------
def _require_fetch(self) -> Callable[[str], dict[str, Any]]:
if self._fetch is None:
raise TypeError("This PaginatedList has no fetcher; cannot walk pages.")
return self._fetch
def iter_all_pages(self) -> Iterator["PaginatedList[T]"]:
"""Yield this page, then every following page via ``next`` links."""
fetch = self._require_fetch()
page: PaginatedList[T] | None = self
while page is not None:
yield page
nxt = page.next_url
page = PaginatedList(fetch(nxt), fetch=fetch) if nxt else None
def iter_all_items(self) -> Iterator[T]:
"""Yield every item across this and all following pages."""
for page in self.iter_all_pages():
yield from page
def fetch_next(self) -> "PaginatedList[T] | None":
"""Fetch the page pointed at by ``next`` (``None`` when absent)."""
nxt = self.next_url
if not nxt:
return None
return PaginatedList(self._require_fetch()(nxt), fetch=self._fetch)
def fetch_prev(self) -> "PaginatedList[T] | None":
prev = self.prev_url
if not prev:
return None
return PaginatedList(self._require_fetch()(prev), fetch=self._fetch)
|
iter_all_pages()
Yield this page, then every following page via next links.
Source code in deezify/paginator.py
| def iter_all_pages(self) -> Iterator["PaginatedList[T]"]:
"""Yield this page, then every following page via ``next`` links."""
fetch = self._require_fetch()
page: PaginatedList[T] | None = self
while page is not None:
yield page
nxt = page.next_url
page = PaginatedList(fetch(nxt), fetch=fetch) if nxt else None
|
iter_all_items()
Yield every item across this and all following pages.
Source code in deezify/paginator.py
| def iter_all_items(self) -> Iterator[T]:
"""Yield every item across this and all following pages."""
for page in self.iter_all_pages():
yield from page
|
fetch_next()
Fetch the page pointed at by next (None when absent).
Source code in deezify/paginator.py
| def fetch_next(self) -> "PaginatedList[T] | None":
"""Fetch the page pointed at by ``next`` (``None`` when absent)."""
nxt = self.next_url
if not nxt:
return None
return PaginatedList(self._require_fetch()(nxt), fetch=self._fetch)
|