Skip to content

Commit 2355715

Browse files
committed
Fix pagination
1 parent 544384c commit 2355715

File tree

6 files changed

+66
-31
lines changed

6 files changed

+66
-31
lines changed

.vscode/launch.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
{
5+
"name": "PyTest",
6+
"type": "python",
7+
"request": "launch",
8+
"cwd": "${workspaceFolder}",
9+
"console": "integratedTerminal",
10+
"module": "pytest",
11+
"env": {},
12+
"justMyCode": false,
13+
"args": [
14+
"-x",
15+
"-vvv",
16+
"tests/test_spaces.py",
17+
],
18+
"debugOptions": [
19+
"RedirectOutput"
20+
]
21+
}
22+
]
23+
}

metablock/client.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66
from typing import Any
77

8-
from aiohttp import ClientSession
8+
from aiohttp import ClientResponse, ClientSession
99
from yarl import URL
1010

1111
from .components import Callback, HttpComponent, MetablockResponseError
@@ -108,6 +108,10 @@ async def request(
108108
response = await self.session.request(method, url, headers=headers_, **kw)
109109
if callback:
110110
return await callback(response)
111+
else:
112+
return await self.handle_response(response, wrap=wrap)
113+
114+
async def handle_response(self, response: ClientResponse, wrap: Any = None) -> Any:
111115
if response.status == 204:
112116
return True
113117
if response.status >= 400:

metablock/components.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
Awaitable,
1010
Callable,
1111
Generic,
12+
Mapping,
1213
TypeVar,
1314
cast,
1415
)
@@ -46,11 +47,11 @@ def __str__(self) -> str:
4647

4748
class HttpComponent(ABC):
4849
@abstractproperty
49-
def cli(self) -> Metablock:
50+
def cli(self) -> Metablock: # pragma: no cover
5051
...
5152

5253
@abstractproperty
53-
def url(self) -> str:
54+
def url(self) -> str: # pragma: no cover
5455
...
5556

5657
def __repr__(self) -> str:
@@ -146,15 +147,14 @@ def __init__(
146147
self.factory = factory
147148

148149
async def paginate(self, **params: Any) -> AsyncIterator[E]:
149-
url = self.list_create_url()
150-
next_ = url
151-
url_params = as_params(**params)
150+
next_ = self.list_create_url()
151+
url_params: Any = as_params(**params)
152152
while next_:
153-
if not next_.startswith(url):
154-
next_ = f'{url}?{next_.split("?")[1]}'
155-
data = await self.cli.request(next_, params=url_params)
156-
next_ = data.get("next")
157-
for d in data["data"]:
153+
next_, data = await self.cli.request(
154+
next_, params=url_params, callback=self._paginated
155+
)
156+
url_params = None
157+
for d in data:
158158
yield self.entity(d)
159159

160160
async def get_list(self, **kwargs: Any) -> list[E]:
@@ -175,7 +175,7 @@ async def get(self, id_: str, **kwargs: Any) -> E:
175175

176176
async def has(self, id_: str, **kwargs: Any) -> bool:
177177
url = f"{self.url}/{id_}"
178-
return cast(bool, await self.cli.get(url, callback=self.head))
178+
return cast(bool, await self.cli.get(url, callback=self._head))
179179

180180
async def create(self, callback: Callback | None = None, **params: Any) -> E:
181181
url = self.list_create_url()
@@ -219,14 +219,6 @@ async def delete_all(self) -> int:
219219
n += 1
220220
return n
221221

222-
async def head(self, response: ClientResponse) -> bool:
223-
if response.status == 404:
224-
return False
225-
elif response.status == 200:
226-
return True
227-
else: # pragma: no cover
228-
raise MetablockResponseError(response)
229-
230222
def entity(self, data: dict) -> E:
231223
return self.factory(self, data)
232224

@@ -241,3 +233,22 @@ def update_url(self, id_name: str) -> str:
241233

242234
def delete_url(self, id_name: str) -> str:
243235
return f"{self.url}/{id_name}"
236+
237+
# callbacks
238+
239+
async def _head(self, response: ClientResponse) -> bool:
240+
if response.status == 404:
241+
return False
242+
elif response.status == 200:
243+
return True
244+
else: # pragma: no cover
245+
raise MetablockResponseError(response)
246+
247+
async def _paginated(self, response: ClientResponse) -> Any:
248+
next = response.links.get("next")
249+
if isinstance(next, Mapping):
250+
url = next.get("url")
251+
else:
252+
url = None
253+
data = await self.cli.handle_response(response)
254+
return (url, data)

metablock/utils.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,6 @@
33
from multidict import MultiDict
44

55

6-
def as_list(key: str, data: dict) -> dict:
7-
v = data.get(key)
8-
if isinstance(v, str):
9-
v = [v]
10-
elif not isinstance(v, list):
11-
v = []
12-
data[key] = v
13-
return data
14-
15-
166
def as_dict(data: Any, key: str = "data") -> dict:
177
return {key: data} if not isinstance(data, dict) else data
188

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![PyPI version](https://badge.fury.io/py/metablock.svg)](https://badge.fury.io/py/metablock)
44
[![Python versions](https://img.shields.io/pypi/pyversions/metablock.svg)](https://pypi.org/project/metablock)
55
[![Build](https://github.com/quantmind/metablock-py/workflows/build/badge.svg)](https://github.com/quantmind/metablock-py/actions?query=workflow%3Abuild)
6-
[![codecov](https://codecov.io/gh/quantmind/metablock-py/branch/master/graph/badge.svg?token=EAdSVpD0Af)](https://codecov.io/gh/quantmind/metablock-py)
6+
[![codecov](https://codecov.io/gh/quantmind/metablock-py/branch/main/graph/badge.svg?token=EAdSVpD0Af)](https://codecov.io/gh/quantmind/metablock-py)
77

88
This is an asynchronous python client for [metablock API](https://api.metablock.io/v1/docs).
99

tests/test_spaces.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ async def test_list_spaces(cli: Metablock) -> None:
77
assert spaces
88

99

10+
async def test_paginate_spaces(cli: Metablock) -> None:
11+
spaces1 = await cli.spaces.get_full_list()
12+
spaces2 = await cli.spaces.get_full_list(limit=1)
13+
assert spaces1
14+
assert len(spaces2) == len(spaces1)
15+
16+
1017
async def test_get_space_403(cli: Metablock, invalid_headers: dict) -> None:
1118
with pytest.raises(MetablockResponseError) as exc:
1219
await cli.spaces.get_list(headers=invalid_headers)

0 commit comments

Comments
 (0)