Skip to content

Add new pagination for watchlist, list items, watched and collection #103

Draft
simonc56 wants to merge 11 commits into
glensc:mainfrom
simonc56:feat/new-pagination
Draft

Add new pagination for watchlist, list items, watched and collection #103
simonc56 wants to merge 11 commits into
glensc:mainfrom
simonc56:feat/new-pagination

Conversation

@simonc56
Copy link
Copy Markdown
Collaborator

🚧 Implementation of new Trakt pagination

Many endpoints need to have pagination with page and limit query parameters, added progressively in 2026 by Trakt devs.

Refs :

Repository owner deleted a comment from coderabbitai Bot May 22, 2026
@simonc56
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Review Change Stack

Warning

Review limit reached

@simonc56, we couldn't start this review because you've used your available PR reviews for now.

Your plan includes 1 review of capacity. Refill in 39 minutes and 49 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 56e16c49-c861-44f1-8b5b-52b00ccf4536

📥 Commits

Reviewing files that changed from the base of the PR and between d1da418 and 2f17b47.

📒 Files selected for processing (3)
  • trakt/_pagination.py
  • trakt/users.py
  • trakt/utils.py

Walkthrough

Adds pagination across the client: new validate_limit helper and a thread-local pagination store; HttpClient parses and stores x-pagination headers; tv/sync/users endpoints accept page/limit and validate limits; Users aggregates paged results and maps items to domain objects; tests and fixtures updated for paginated flows.

Changes

Pagination Support Implementation

Layer / File(s) Summary
Pagination limit validation utility
trakt/utils.py
New validate_limit(limit) and _MAX_LIMIT = 250 exported in __all__.
Internal pagination store
trakt/_pagination.py
Thread-local get()/set() for per-thread pagination state.
HttpClient pagination parsing
trakt/api.py
HttpClient.request clears pagination, returns None on 204, parses x-pagination-* headers into Pagination, and stores it via the internal store; adds header-parsing helper.
Core export for pagination
trakt/core.py
Add and export get_pagination() delegating to utils to return the last response's pagination.
TV module limit validation
trakt/tv.py
Insert validate_limit(limit) calls across TV listing endpoints that accept limit.
Sync module pagination support
trakt/sync.py
get_watchlist, get_watched, and get_collection accept page/limit (and watchlist sorting params), validate inputs, and build query strings; deprecated decorator removed from get_watched.
Users imports and URI normalization
trakt/users.py (top)
Normalize imports/exports, add pagination helpers, and standardize templated URI strings for request helpers.
PublicList / UserList pagination support
trakt/users.py (PublicList/UserList)
PublicList._load_items and UserList.get_items accept page/limit, validate limit, request paginated /items, map returned type fields to domain objects, and reset pagination state.
User parsing and helpers
trakt/users.py (User helpers)
Add validation and _parse_* helpers; update cached attributes and centralize parsing of watchlist/collection/watched payloads into domain objects (including season/episode parsing).
User aggregation properties
trakt/users.py (collection/watchlist/watched)
Refactor movie/show collection and watched/watchlist properties to aggregate across pages via iter_pages and parsing helpers; normalize follower/list endpoints.
Mock data fixtures for paginated endpoints
tests/mock_data/*.json
Remap non-paginated keys to paginated endpoint keys and add multi-page fixtures (including empty pages) for lists, sync, and users.
Tests and conftest updates
tests/conftest.py, tests/test_sync.py, tests/test_users.py
Clear pagination state between mocked requests; add tests for get_watchlist/get_collection/get_watched and extend user tests to assert paginated behaviors and empty page responses.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • glensc/python-pytrakt#51: Prior work introducing HttpClient behaviors that this PR extends by parsing/storing pagination headers.

Poem

🐇 I hopped through pages, from one into two,

validate_limit kept my bounds straight and true,
HttpClient stores the headers I find,
Users stitched pages into lists, all aligned,
Tests and fixtures danced — a paged API view.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main focus of the changeset: adding pagination support to watchlist, list items, watched, and collection endpoints.
Description check ✅ Passed The description is directly related to the changeset, explaining the implementation of new Trakt pagination with page and limit parameters and providing relevant references.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
trakt/users.py (1)

193-206: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

items now truncates public lists to the first page.

items, __iter__, and __len__ still behave like whole-list accessors, but this property now only loads page=1&limit=100. Any public list with more than 100 entries will be silently incomplete, and PublicList doesn't expose a public paginated reader to fetch the rest.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trakt/users.py` around lines 193 - 206, The items property currently only
loads the first page (page=1, limit=100) causing PublicList to be truncated;
update _load_items (and keep items, __iter__, __len__ semantics) to fetch all
pages by iterating page numbers from 1 upward, calling the existing yield
"lists/{self.trakt}/items?page={page}&limit={limit}" inside _load_items and
accumulating results into self._items until a page returns fewer than limit
items (or empty), and preserve validate_limit(limit) and _process_items usage;
alternatively, expose a paginated reader method on PublicList if you prefer lazy
access, but ensure callers to items, __iter__, and __len__ see the full list
rather than only page 1.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_users.py`:
- Around line 39-44: The test uses all([...]) which returns True for empty
lists, so add explicit non-empty checks for the page results before the
membership assertions: ensure movie_page and show_page are not empty (e.g.,
assert movie_page and assert show_page or assert len(movie_page) > 0 and
len(show_page) > 0) prior to the existing all(...) checks for 'movie' and 'show'
to guard against vacuous passes; update the assertions around the variables
movie_page and show_page in tests/test_users.py accordingly.

In `@trakt/sync.py`:
- Around line 419-420: The get_watchlist function accepts a limit but doesn't
enforce the max-limit guard; call validate_limit(limit) at the start of
get_watchlist (and use its returned/validated value) before any paging logic,
and apply the same change to the other two paginated sync endpoints in this
module that accept a limit (the functions defined just after get_watchlist
around the following sync blocks) so all three use validate_limit() to
clamp/validate the provided limit.
- Around line 449-455: The URI construction in get_watchlist appends
'?sort_how=...' and then unconditionally prepends '?' again for page/limit,
producing an invalid query string; fix by consolidating query parameters instead
of appending raw strings: add sort_how into the params dict when provided (or
check if '?' already in uri and use '&' instead), then build the final query
string once using the params dict (the symbols to change are get_watchlist,
sort_how, params, and uri).

In `@trakt/users.py`:
- Around line 762-766: When constructing the TVEpisode payload, the show Trakt
id is nested under sh_data["ids"]["trakt"], so replace the current
sh_data.get("trakt") usage with a safe nested lookup (e.g., sh_data.get("ids",
{}).get("trakt")) when updating ep_data (the ep_data.update(...,
show=sh_data.get("title"), show_id=... ) call) so the show_id is preserved for
TVEpisode creation.
- Around line 279-323: get_items currently appends parsed items into the shared
cache attribute self._items causing page results to accumulate and duplicate;
instead create a fresh local list (e.g. items = []) inside get_items, append
parsed Movie/TVShow/TVSeason/TVEpisode/Person instances to that local list
(replace all self._items.append calls), do not modify self._items, and
yield/return the local list so each get_items(page=...) call returns only that
page's items; keep references to get_items and the _items attribute to locate
the changes.

---

Outside diff comments:
In `@trakt/users.py`:
- Around line 193-206: The items property currently only loads the first page
(page=1, limit=100) causing PublicList to be truncated; update _load_items (and
keep items, __iter__, __len__ semantics) to fetch all pages by iterating page
numbers from 1 upward, calling the existing yield
"lists/{self.trakt}/items?page={page}&limit={limit}" inside _load_items and
accumulating results into self._items until a page returns fewer than limit
items (or empty), and preserve validate_limit(limit) and _process_items usage;
alternatively, expose a paginated reader method on PublicList if you prefer lazy
access, but ensure callers to items, __iter__, and __len__ see the full list
rather than only page 1.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d3c1feeb-2608-4af1-a8c9-f12990626087

📥 Commits

Reviewing files that changed from the base of the PR and between 2c7091c and a27ca9d.

📒 Files selected for processing (8)
  • tests/mock_data/lists.json
  • tests/mock_data/sync.json
  • tests/mock_data/users.json
  • tests/test_users.py
  • trakt/sync.py
  • trakt/tv.py
  • trakt/users.py
  • trakt/utils.py

Comment thread tests/test_users.py
Comment thread trakt/sync.py
Comment thread trakt/sync.py
Comment thread trakt/users.py Outdated
Comment thread trakt/users.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
trakt/sync.py (1)

445-453: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject sort_how when sort_by is not provided.

Right now sort_how is ignored unless sort_by is set. That silently drops caller input instead of surfacing invalid usage.

💡 Suggested fix
+    if sort_how is not None and sort_by is None:
+        raise ValueError("sort_how requires sort_by")
+
     if sort_by is not None:
         if sort_by not in WATCHLIST_SORT_BY:
             raise ValueError('sort_by must be one of {}'.format(WATCHLIST_SORT_BY))
         uri += '/{}'.format(sort_by)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trakt/sync.py` around lines 445 - 453, Ensure callers cannot pass sort_how
without sort_by: add an explicit validation that raises a ValueError when
sort_how is not None but sort_by is None (before building uri), then keep the
existing checks that validate sort_by against WATCHLIST_SORT_BY and sort_how
being "asc"/"desc" and append them to uri as before; reference the sort_by and
sort_how variables and WATCHLIST_SORT_BY constant in the function that builds
the uri so invalid usage is surfaced instead of silently ignored.
tests/mock_data/users.json (1)

736-767: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add paginated fixture keys for watchlist seasons/episodes to match new request shape.

On Line 736 and Line 752, only unpaginated keys are present. User.watchlist() now always calls .../watchlist/{media_type}?page=...&limit=..., so seasons/episodes fixtures should include paginated keys too.

Suggested fixture additions
+    "users/sean/watchlist/seasons?page=1&limit=100": {
+        "GET": [
+            ...
+        ]
+    },
+    "users/sean/watchlist/episodes?page=1&limit=100": {
+        "GET": [
+            ...
+        ]
+    },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/mock_data/users.json` around lines 736 - 767, The fixtures for
watchlist seasons/episodes only include unpaginated keys
("users/sean/watchlist/seasons" and "users/sean/watchlist/episodes"); add
matching paginated keys that User.watchlist() now requests (e.g.
"users/sean/watchlist/seasons?page=1&limit=10" and
"users/sean/watchlist/episodes?page=1&limit=10") with the same payload arrays so
the tests see responses for paged requests.
♻️ Duplicate comments (1)
trakt/users.py (1)

292-338: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

get_items(page=...) still returns accumulated cache instead of page-scoped results.

On Line 292, get_items accepts page, but from Line 313 onward it appends into self._items and yields that shared list. Calling get_items(page=2) after page 1 returns combined data, and repeated calls can duplicate entries.

Suggested fix
 `@get`
 def get_items(self, page=1, limit=100):
@@
-    if not data:
-        yield self._items
+    if not data:
+        yield []
 
+    items = []
     for item in data:
@@
-            self._items.append(
+            items.append(
                 Movie(
                     item_data["title"], item_data["year"], item_data["ids"]["slug"]
                 )
             )
         elif item_type == "show":
-            self._items.append(TVShow(item_data["title"], item_data["ids"]["slug"]))
+            items.append(TVShow(item_data["title"], item_data["ids"]["slug"]))
@@
-            self._items.append(season)
+            items.append(season)
@@
-            self._items.append(episode)
+            items.append(episode)
         elif item_type == "person":
-            self._items.append(Person(item_data["name"], item_data["ids"]["slug"]))
+            items.append(Person(item_data["name"], item_data["ids"]["slug"]))
 
-    yield self._items
+    yield items
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trakt/users.py` around lines 292 - 338, get_items is appending page results
into the shared cache self._items which causes pages to accumulate and
duplicate; change the implementation to collect results in a local list (e.g.
items = []) instead of appending to self._items, populate that local list for
each item_type branch (Movie, TVShow, TVSeason, TVEpisode, Person) and yield
that local list at the end; do not mutate self._items when building page-scoped
results (you can keep the existing early branch that yields self._items when no
data is returned).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_users.py`:
- Around line 63-70: The test uses an ambiguous single-letter variable name `l`
which triggers Ruff E741; rename the variable to a descriptive identifier (e.g.,
`user_list` or `retrieved_list`) in both places where it's assigned from
UserList.get(...) and sean.get_list(...), and update all subsequent references
(the len(list(...)) call and the getattr checks) to use that new name; this
affects the occurrences tied to the UserList.get and sean.get_list results.

In `@trakt/api.py`:
- Around line 139-141: Clear the stale pagination metadata before potential HTTP
errors by resetting _pagination_store (call its clear/reset method or set to
None) immediately before calling self.raise_if_needed(response), then after
raise_if_needed succeeds call
_pagination_store.set(self._parse_pagination_headers(response.headers)) and
return self.decode_response(response); reference _pagination_store,
self.raise_if_needed, _parse_pagination_headers, and decode_response so you
update the pagination state only on successful responses.

---

Outside diff comments:
In `@tests/mock_data/users.json`:
- Around line 736-767: The fixtures for watchlist seasons/episodes only include
unpaginated keys ("users/sean/watchlist/seasons" and
"users/sean/watchlist/episodes"); add matching paginated keys that
User.watchlist() now requests (e.g.
"users/sean/watchlist/seasons?page=1&limit=10" and
"users/sean/watchlist/episodes?page=1&limit=10") with the same payload arrays so
the tests see responses for paged requests.

In `@trakt/sync.py`:
- Around line 445-453: Ensure callers cannot pass sort_how without sort_by: add
an explicit validation that raises a ValueError when sort_how is not None but
sort_by is None (before building uri), then keep the existing checks that
validate sort_by against WATCHLIST_SORT_BY and sort_how being "asc"/"desc" and
append them to uri as before; reference the sort_by and sort_how variables and
WATCHLIST_SORT_BY constant in the function that builds the uri so invalid usage
is surfaced instead of silently ignored.

---

Duplicate comments:
In `@trakt/users.py`:
- Around line 292-338: get_items is appending page results into the shared cache
self._items which causes pages to accumulate and duplicate; change the
implementation to collect results in a local list (e.g. items = []) instead of
appending to self._items, populate that local list for each item_type branch
(Movie, TVShow, TVSeason, TVEpisode, Person) and yield that local list at the
end; do not mutate self._items when building page-scoped results (you can keep
the existing early branch that yields self._items when no data is returned).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a36b8c07-0066-45d2-98bc-0bc40cce772d

📥 Commits

Reviewing files that changed from the base of the PR and between a27ca9d and e39b4c0.

📒 Files selected for processing (12)
  • tests/conftest.py
  • tests/mock_data/lists.json
  • tests/mock_data/sync.json
  • tests/mock_data/users.json
  • tests/test_sync.py
  • tests/test_users.py
  • trakt/_pagination.py
  • trakt/api.py
  • trakt/core.py
  • trakt/sync.py
  • trakt/users.py
  • trakt/utils.py

Comment thread tests/test_users.py Outdated
Comment thread trakt/api.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
trakt/users.py (2)

209-211: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing early return after yielding empty result.

When data is falsy, the code yields [] but execution continues to line 211, which attempts to process data anyway. If data is None, _process_items will fail; if data is [], you get a redundant second yield.

Suggested fix
     if not data:
         yield []
+        return
     yield list(self._process_items(data))

Or alternatively use an else clause:

     if not data:
         yield []
+    else:
-    yield list(self._process_items(data))
+        yield list(self._process_items(data))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trakt/users.py` around lines 209 - 211, The generator yields an empty list
when data is falsy but then continues and yields again by calling
self._process_items(data), causing errors or duplicate yields; fix by returning
immediately after yielding the empty list (or use an else) so execution stops —
update the block containing the falsy-data check to `if not data: yield [];
return` (or `if not data: yield []; else: yield
list(self._process_items(data))`) to prevent calling _process_items with None or
yielding twice.

468-476: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Potential NameError and TypeError on edge cases.

Multiple issues in this loop:

  1. Line 472: season.get("episodes") returns None if key is missing, causing TypeError when iterating.
  2. Line 476: del te, ts, full_show will raise NameError if seasons is empty (ts never assigned) or all seasons have no episodes (te never assigned).
Suggested fix
         full_show = TVShow(**show_item)
+        te = ts = None  # Initialize to avoid NameError on del
         for season in seasons:
             ts = next(
                 s for s in full_show.seasons if s.season == season.get("number")
             )
-            for ep in season.get("episodes"):
+            for ep in season.get("episodes", []):
                 te = next(e for e in ts.episodes if e.number == ep.get("number"))
                 ep["title"] = te.title
                 ep.update(te.ids)
         del te, ts, full_show

Alternatively, remove the del statement entirely—Python's garbage collector will handle cleanup when variables go out of scope.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@trakt/users.py` around lines 468 - 476, The loop can raise TypeError when
season.get("episodes") is None and NameError from the final del if ts/te were
never assigned; update the inner loop to iterate over season.get("episodes", [])
instead of season.get("episodes") and remove the cleanup statement del te, ts,
full_show (or if you prefer, conditionally delete only if those names exist) so
variables are not referenced when they were never set; target the for seasons
loop and the variables ts, te, full_show in trakt/users.py.
tests/test_users.py (1)

148-149: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add explicit non-empty assertions before all() checks.

Lines 148-149 are missing the explicit non-empty assertions that were added to test_user_collections (lines 41-42) and test_user_watchlists (lines 124-125). Without these guards, all([...]) will vacuously pass if page 1 returns empty results, masking pagination regressions.

🛡️ Proposed fix to match sibling tests
     movie_page = sean.watched('movies', page=1, limit=250)
     show_page = sean.watched('shows', page=1, limit=250)
+    assert movie_page
+    assert show_page
     assert all(['movie' in item for item in movie_page])
     assert all(['show' in item for item in show_page])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_users.py` around lines 148 - 149, Add explicit non-empty
assertions for the paged results before any all(...) checks: after obtaining
movie_page = sean.watched('movies', page=1, limit=250) and show_page =
sean.watched('shows', page=1, limit=250) assert the returned page results are
non-empty (e.g., check movie_page['results'] and show_page['results'] or
equivalent attributes) so the subsequent all(...) checks cannot vacuously pass;
update the test to mirror the guards used in test_user_collections and
test_user_watchlists while keeping the calls to sean.watched unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@trakt/users.py`:
- Around line 294-295: The generator currently yields an empty list when data is
falsy but doesn't stop execution (the line "if not data: yield []"), causing
subsequent code to run on None; after yielding the empty result you must
return/stop the generator to prevent further processing—update the block
containing "if not data: yield []" in trakt/users.py to yield the empty list and
then immediately return (or otherwise stop iteration) so downstream code in that
generator won't execute when data is None.

---

Outside diff comments:
In `@tests/test_users.py`:
- Around line 148-149: Add explicit non-empty assertions for the paged results
before any all(...) checks: after obtaining movie_page = sean.watched('movies',
page=1, limit=250) and show_page = sean.watched('shows', page=1, limit=250)
assert the returned page results are non-empty (e.g., check
movie_page['results'] and show_page['results'] or equivalent attributes) so the
subsequent all(...) checks cannot vacuously pass; update the test to mirror the
guards used in test_user_collections and test_user_watchlists while keeping the
calls to sean.watched unchanged.

In `@trakt/users.py`:
- Around line 209-211: The generator yields an empty list when data is falsy but
then continues and yields again by calling self._process_items(data), causing
errors or duplicate yields; fix by returning immediately after yielding the
empty list (or use an else) so execution stops — update the block containing the
falsy-data check to `if not data: yield []; return` (or `if not data: yield [];
else: yield list(self._process_items(data))`) to prevent calling _process_items
with None or yielding twice.
- Around line 468-476: The loop can raise TypeError when season.get("episodes")
is None and NameError from the final del if ts/te were never assigned; update
the inner loop to iterate over season.get("episodes", []) instead of
season.get("episodes") and remove the cleanup statement del te, ts, full_show
(or if you prefer, conditionally delete only if those names exist) so variables
are not referenced when they were never set; target the for seasons loop and the
variables ts, te, full_show in trakt/users.py.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fe553d49-8d66-45c7-aaf4-8eeab9c2c97d

📥 Commits

Reviewing files that changed from the base of the PR and between e39b4c0 and d1da418.

📒 Files selected for processing (7)
  • tests/mock_data/lists.json
  • tests/mock_data/users.json
  • tests/test_lists.py
  • tests/test_users.py
  • trakt/api.py
  • trakt/users.py
  • trakt/utils.py
✅ Files skipped from review due to trivial changes (2)
  • tests/test_lists.py
  • trakt/utils.py

Comment thread trakt/users.py
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.

1 participant