Skip to content

feat: add async Deezer client and resources in deezer.asyncio#1565

Merged
browniebroke merged 42 commits intomainfrom
claude/async-deezer-client-SmYVB
Apr 6, 2026
Merged

feat: add async Deezer client and resources in deezer.asyncio#1565
browniebroke merged 42 commits intomainfrom
claude/async-deezer-client-SmYVB

Conversation

@browniebroke
Copy link
Copy Markdown
Owner

@browniebroke browniebroke commented Apr 4, 2026

  • Extract shared client logic into a DeezerMixin class, and create an AsyncClient inheriting from both DeezerMixin and httpx.AsyncClient.
  • Introduce async resources providing awaitable methods to traverse relationships
  • Provide an async paginated list class with similar API as the sync one
  • Documentation and test

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b

Fix #1339
Ref #804

claude added 12 commits April 3, 2026 13:15
Extract shared client logic (objects_types, _process_json) into a DeezerMixin
class, then create an AsyncClient inheriting from both DeezerMixin and
httpx.AsyncClient. Includes get_album() method and async tests with VCR
cassettes.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Move test_async_client.py to tests/asyncio/test_client.py and cassettes
to tests/asyncio/cassettes/ to match the deezer.asyncio package layout.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Replace manual vcr.use_cassette() context managers with pytestmark =
pytest.mark.vcr, matching the pattern used by the sync tests. Add
async_client fixture in conftest and per-test cassette files.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
…tist

Create deezer.asyncio.resources sub-package mirroring the sync resources
layout. AsyncResource provides async get_relation(). AsyncAlbum has
async get_artist() and get_tracks() methods. AsyncClient now returns
async resource types via overridden objects_types.

Add _resource_base_class to DeezerMixin so the async client falls back
to AsyncResource for unknown types.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
AsyncArtist now has get_top(), get_related(), get_radio(), get_albums(),
and get_playlists() async methods. Add post_relation/delete_relation to
AsyncResource base. Add get_artist() to AsyncClient.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @browniebroke, your pull request is larger than the review limit of 150000 diff characters

Comment thread src/deezer/asyncio/client.py Dismissed
Comment thread src/deezer/asyncio/pagination.py Dismissed
Comment thread src/deezer/asyncio/pagination.py Dismissed
Comment thread src/deezer/asyncio/resources/album.py Dismissed
Comment thread src/deezer/asyncio/resources/artist.py Dismissed
Comment thread src/deezer/asyncio/resources/resource.py Dismissed
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.92%. Comparing base (c0abb24) to head (612572e).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1565      +/-   ##
==========================================
+ Coverage   99.86%   99.92%   +0.06%     
==========================================
  Files          20       37      +17     
  Lines         723     1332     +609     
  Branches       46       71      +25     
==========================================
+ Hits          722     1331     +609     
  Partials        1        1              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

claude and others added 11 commits April 4, 2026 15:45
Implements AsyncPlaylist with get_tracks, get_fans, mark_seen, add_tracks,
delete_tracks, and reorder_tracks methods. Adds get_playlist to AsyncClient.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Implements AsyncUser with get/add/remove methods for albums, tracks, artists,
playlists, followers, followings, and create_playlist. Adds get_user to
AsyncClient and async_client_token fixture for authenticated async tests.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Implements AsyncPaginatedList with async iteration (__aiter__/__anext__),
total(), length(), get() for indexed access, and collect() to fetch all pages.
Mirrors the sync PaginatedList but uses async methods throughout.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Adds get_paginated_list() to AsyncResource for building AsyncPaginatedList
from relation methods, and _get_paginated_list() to AsyncClient as a
convenience for client-level paginated queries.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
- resource.py: Move AsyncPaginatedList import to top level (no circular dep)
- editorial.py: Move AsyncChart import to top level (no circular dep)
- album.py: Remove empty TYPE_CHECKING block and unused typing import

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Updates all async resource methods that correspond to sync methods returning
PaginatedList to now return AsyncPaginatedList instead of plain lists.

Affected resources: Album, Artist, Chart, Editorial, Genre, Playlist,
Podcast, User. Methods like get_radio, get_selection, get_artists (on Genre)
that use get_relation in sync are left unchanged.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Adds all remaining sync Client methods to AsyncClient:
- Search: search, search_albums, search_artists, search_playlists
- Lists: list_editorials, list_genres, list_radios, get_radios_top
- User recommendations: get_user_recommended_tracks/albums/artists/playlists
- User favorites: get_user_albums/artists/tracks with add/remove variants
- User social: get_user_followers/followings with add/remove_user_following
- User misc: get_user_flow, get_user_history
- Playlists: create_playlist, delete_playlist, add/remove_user_playlist

All paginated methods return AsyncPaginatedList, matching sync behavior.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
- Use ty: ignore syntax for invalid-method-override on AsyncClient.request
- Widen type annotations on AsyncClient.request to accept AsyncResource types
- Use Any for parent/resource_type params in DeezerMixin._process_json since
  it's shared between sync (Resource) and async (AsyncResource) clients

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
@browniebroke browniebroke force-pushed the claude/async-deezer-client-SmYVB branch from 3e4ccc3 to 5cf2c45 Compare April 4, 2026 15:45
claude and others added 5 commits April 4, 2026 15:58
Cover previously untested lines in AsyncPaginatedList:
- __repr__ method (lines 35-39)
- __anext__ raising StopAsyncIteration (line 69)

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
…aylist reorder_tracks

Cover previously untested lines:
- AsyncEditorial.get_chart (line 29)
- AsyncGenre.get_podcasts (line 28)
- AsyncPlaylist.reorder_tracks (lines 60-61)

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
- Add advanced search test (no query, only artist param) for _search branch
- Add second __anext__ call after exhaustion to cover _could_grow() False branch

All asyncio code now at 100% line and branch coverage.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
- Add docs/async.md covering AsyncClient, async resources, and
  AsyncPaginatedList usage with practical examples
- Add API reference pages for AsyncClient, AsyncPaginatedList, and all
  11 async resource classes using autodoc
- Update index.md to include async guide after pagination page
- Update API reference TOC to include async sections

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
claude added 4 commits April 4, 2026 18:41
…t page fetch

AsyncPaginatedList now fetches the first page eagerly via a new
`create()` classmethod factory. All methods on AsyncClient and async
resources that return an AsyncPaginatedList are now async and must
be awaited, matching user expectations for async code.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
All tests now await paginated list creation calls, matching the new
behavior where methods returning AsyncPaginatedList are async and
eagerly fetch the first page. Updated AsyncPaginatedList fixture to
use the create() classmethod factory.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
- Remove unreachable _could_grow() guard in create() factory
- Remove dead total() fallback that fetched with limit=1 since total
  is always available from the first page
- Add cross-page __anext__ test for full iterator coverage
- Update docs/async.md to reflect awaitable pagination behavior

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Since AsyncPaginatedList eagerly fetches the first page, total is
always available synchronously. Replace async total() method with a
property and replace length() with __len__ to match the sync API.

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
Align with the sync PaginatedList convention of using name-mangled
private attributes (e.g. self.__elements instead of self._elements).

https://claude.ai/code/session_011tWs29w53Yg2dmkQqUV79b
@browniebroke browniebroke changed the title feat: add async Deezer client in deezer.asyncio sub-package feat: add async Deezer client and resources in deezer.asyncio Apr 6, 2026
@browniebroke browniebroke merged commit cf30c7c into main Apr 6, 2026
20 checks passed
@browniebroke browniebroke deleted the claude/async-deezer-client-SmYVB branch April 6, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Propose an async client

3 participants