Skip to content

Commit

Permalink
update aiorequestful version
Browse files Browse the repository at this point in the history
  • Loading branch information
geo-martino committed Jul 10, 2024
1 parent b164197 commit bbfaa94
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 22 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pip install musify
python -m pip install musify
```

There are alo optional dependencies that you may install for optional functionality.
There are optional dependencies that you may install for optional functionality.
For the current list of optional dependency groups, [read the docs](https://geo-martino.github.io/musify/howto.install.html)


Expand Down
2 changes: 1 addition & 1 deletion README.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pip install {program_name_lower}
python -m pip install {program_name_lower}
```

There are alo optional dependencies that you may install for optional functionality.
There are optional dependencies that you may install for optional functionality.
For the current list of optional dependency groups, [read the docs](https://{program_owner_user}.github.io/{program_name_lower}/howto.install.html)


Expand Down
9 changes: 8 additions & 1 deletion musify/libraries/remote/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from aiorequestful.auth import Authoriser
from aiorequestful.cache.backend.base import ResponseCache
from aiorequestful.cache.exception import CacheError
from aiorequestful.cache.session import CachedSession
from aiorequestful.request.handler import RequestHandler
from aiorequestful.response.payload import JSONPayloadHandler
from aiorequestful.types import ImmutableJSON, JSON
Expand Down Expand Up @@ -87,7 +88,7 @@ def __init__(self, authoriser: A, wrangler: RemoteDataWrangler, cache: ResponseC

#: The :py:class:`RequestHandler` for handling authorised requests to the API
self.handler: RequestHandler[A, JSON] = RequestHandler.create(
authoriser=authoriser, cache=cache, payload_handler=JSONPayloadHandler(),
authoriser=authoriser, cache=cache, payload_handler=JSONPayloadHandler(indent=2),
)

#: Stores the loaded user data for the currently authorised user
Expand All @@ -103,6 +104,12 @@ async def __aenter__(self) -> Self:
except CacheError:
pass

if isinstance(self.handler.session, CachedSession):
for repository in self.handler.session.cache.values():
# all repositories must use the same payload handler as the request handler
# for it to function correctly
repository.settings.payload_handler = self.handler.payload_handler

await self.load_user()
await self.load_user_playlists()

Expand Down
2 changes: 1 addition & 1 deletion musify/libraries/remote/spotify/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,4 @@ async def _cache_responses(self, method: str, responses: Iterable[dict[str, Any]
url=url,
message=f"Caching {len(results_mapped)} to {repository.settings.name!r} repository",
)
await repository.save_responses({k: repository.serialize(v) for k, v in results_mapped.items()})
await repository.save_responses({k: await repository.serialize(v) for k, v in results_mapped.items()})
9 changes: 4 additions & 5 deletions musify/libraries/remote/spotify/api/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ def get_key(self, method: MethodInput, url: URLInput, **__) -> tuple[str | None,
pass
return (None,)

@staticmethod
def get_name(response: dict[str, Any]) -> str | None:
if response.get("type") == "user":
return response["display_name"]
return response.get("name")
def get_name(self, payload: dict[str, Any]) -> str | None:
if payload.get("type") == "user":
return payload["display_name"]
return payload.get("name")


class SpotifyPaginatedRepositorySettings(SpotifyRepositorySettings):
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ classifiers = [
]
dependencies = [
"mutagen~=1.47",
"aiorequestful~=0.4",
"aiorequestful~=0.5",
"python-dateutil~=2.9",
"Pillow~=10.3",
]
Expand All @@ -43,7 +43,7 @@ musicbee = [
"lxml~=5.2",
]
sqlite = [
"aiorequestful[sqlite]~=0.4",
"aiorequestful[sqlite]~=0.5",
]

# dev dependencies
Expand Down
24 changes: 23 additions & 1 deletion tests/libraries/remote/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from urllib.parse import unquote

import pytest
from aiorequestful.cache.backend import ResponseCache
from yarl import URL

from musify.libraries.remote.core.api import RemoteAPI
Expand Down Expand Up @@ -39,6 +40,17 @@ def object_factory(self) -> RemoteObjectFactory:
"""Yield the object factory for objects of this remote service type as a pytest.fixture."""
raise NotImplementedError

@pytest.fixture
async def api_cache(self, api: RemoteAPI, cache: ResponseCache, api_mock: RemoteMock) -> RemoteAPI:
"""Yield an authorised :py:class:`RemoteAPI` object with a :py:class:`ResponseCache` configured."""
api_cache = api.__class__(cache=cache)
api_cache.handler.authoriser.response_handler = api.handler.authoriser.response_handler

async with api_cache as a:
# entering context sometimes makes HTTP calls, reset to avoid issues asserting request counts
api_mock.reset()
yield a

@pytest.fixture
def _responses(self, object_type: RemoteObjectType, api_mock: RemoteMock) -> dict[str, dict[str, Any]]:
"""Yields valid responses mapped by ID for a given ``object_type`` as a pytest.fixture."""
Expand Down Expand Up @@ -73,7 +85,7 @@ def key(self, object_type: RemoteObjectType, extend: bool, api: RemoteAPI) -> st
return api.collection_item_map[object_type].name.lower() + "s" if extend else None


class RemoteAPIItemTester(metaclass=ABCMeta):
class RemoteAPIItemTester(RemoteAPIFixtures, metaclass=ABCMeta):
"""Run generic tests for item methods of :py:class:`RemoteAPI` implementations."""
###########################################################################
## Assertions
Expand Down Expand Up @@ -102,6 +114,16 @@ def assert_params(requests: Iterable[URL], params: dict[str, Any] | list[dict[st
assert k in url.query
assert unquote(url.query[k]) == params[k]

def test_context_management(self, api_cache: RemoteAPI):
session = api_cache.handler.session

assert session.cache.values()
for repository in session.cache.values():
assert repository.settings.payload_handler == api_cache.handler.payload_handler

assert api_cache.user_data
assert api_cache.user_playlist_data


class RemoteAPIPlaylistTester(metaclass=ABCMeta):
"""Run generic tests for playlist methods of :py:class:`RemoteAPI` implementations."""
Expand Down
10 changes: 0 additions & 10 deletions tests/libraries/remote/spotify/api/testers.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,6 @@ async def repository(
"""Yields a valid :py:class:`ResponseCache` to use throughout tests in this suite as a pytest.fixture."""
return cache.get_repository_from_url(response[self.url_key])

@pytest.fixture
async def api_cache(self, api: SpotifyAPI, cache: ResponseCache, api_mock: SpotifyMock) -> SpotifyAPI:
"""Yield an authorised :py:class:`SpotifyAPI` object with a :py:class:`ResponseCache` configured."""
api_cache = SpotifyAPI(cache=cache)
api_cache.handler.authoriser.response_handler = api.handler.authoriser.response_handler

async with api_cache as a:
api_mock.reset() # entering context calls '/me' endpoint, reset to avoid issues asserting request counts
yield a

@pytest.fixture
def responses(self, _responses: dict[str, dict[str, Any]], key: str) -> dict[str, dict[str, Any]]:
return {id_: response for id_, response in _responses.items() if key is None or response[key]["total"] > 3}
Expand Down

0 comments on commit bbfaa94

Please sign in to comment.