Migrate to external rohlik-api package, remove internal client - #76
Conversation
Replace the in-tree 706-line RohlikCZAPI client (and its errors module) with the published rohlik-api PyPI package, and rework the integration to consume the package's service-based API and typed models directly: - manifest: depend on rohlik-api==0.1.0. - hub: drive RohlikAPI (per-account HA-managed session with its own cookie jar, lazy login + transparent 401 re-auth); map InvalidCredentialsError / RohlikAPIError to ConfigEntryAuthFailed / UpdateFailed; reimplement the order-history enrichment orchestration on top of the package primitives (orders.get_all_delivered / orders.get_detail / products.get_categories); refresh_slots via delivery.get_next_slots; close the session on unload. - config_flow: validate credentials via RohlikAPI.login(). - sensor/todo: consume the Cart model (attributes) instead of a dict. - services: convert returned models to dicts at the HA response boundary. - tests: patch the new client surface; cart fixture is now a Cart model; drop the internal-client unit tests (now covered by the package's repo). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqvRozwrnqt3NgyaYeBZe
The rohlik-api dependency declares requires-python >=3.13. HA mandates Python 3.13 from 2025.2 onward, so bump the HACS minimum and README badge to match and avoid installs failing on a 3.12 runtime. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqvRozwrnqt3NgyaYeBZe
|
@claude review Generated by Claude Code |
|
Claude finished @dvejsada's task in 3m 10s —— View job PR Review
Overall this is a clean, well-reasoned migration. The session-per-account isolation, lazy login, and transparent 401 re-auth are all correct HA patterns. The lock split (store lock vs. enrich lock) is well thought out. A few issues worth addressing below. Medium Issues1. Session leak in async def async_close(self) -> None:
await self._client.close() # ← if this raises, session is never closed
await self._session.close()If the package's async def async_close(self) -> None:
try:
await self._client.close()
finally:
await self._session.close()2. # hub.py
added = await self._client.cart.add_items([...])
return {"added_products": added} # ← added is returned raw, no asdict()The PR correctly uses Minor Issues3. Progress callback fires at if progress_callback and i % 50 == 0: # ← triggers immediately at i=0
await progress_callback(i, total)The first persistent notification immediately reports 4. Legacy from typing import Any, Optional, DictPython 3.13 is now the minimum. 5.
6. Test fixture The fixture sets Positive Highlights
|
The integration now depends on rohlik-api at runtime; the test workflow installs requirements_test.txt only, so add the package there to fix the ModuleNotFoundError during test collection. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqvRozwrnqt3NgyaYeBZe
- async_close: close the HA-managed session in a finally so a failing client.close() (e.g. logout timeout) can't leak it. - config_flow: map RohlikAPIError to the existing cannot_connect error string instead of falling through to 'unknown' (both user + reauth steps); add a test for it. - _fetch_product_categories: don't fire the progress callback at i=0. - hub: drop unused Optional/Dict typing imports, use lowercase dict. - tests: make the bags fixture match the shape the sensor reads (current/max). cart.add_items returns list[int] (plain primitives), so the add_to_cart service response needs no asdict() - left as-is. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqvRozwrnqt3NgyaYeBZe
|
Thanks for the thorough review — addressed in
Suite green at 22 passed (added the Generated by Claude Code |
|
@claude review Generated by Claude Code |
|
Claude finished @dvejsada's task in 2m 31s —— View job PR Review
All six findings from the prior round are correctly resolved. The code is in excellent shape. Two minor nits remain from this pass: Minor Issues1.
from typing import List, Dict, Any # line 4
async def async_add_to_cart_service(call: ServiceCall) -> List[int]: # line 33
async def async_search_product_service(call: ServiceCall) -> Dict[str, Any]: # line 48
# ...Python 3.13 is now the minimum, so these should be 2. async def async_add_to_cart_service(call: ServiceCall) -> List[int]:
...
result = await account.add_to_cart(product_id, quantity)
return result # hub.add_to_cart returns {"added_products": list[int]}The service returns the Verified Correct
Positive Highlights
The two nits above are cosmetic and won't affect runtime behaviour. This is otherwise merge-ready. |
Drop legacy List/Dict typing imports in favour of lowercase built-ins, and fix async_add_to_cart_service's return hint (it returns the dict from hub.add_to_cart, not a list[int]). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqvRozwrnqt3NgyaYeBZe
|
Both cosmetic nits from the last review are fixed in
CI is green on Generated by Claude Code |
0.2.0 fixes delivery.get_next_slots() returning None for accounts whose login response omits a delivery address (it now falls back to the saved address list). The integration already calls get_next_slots(), so it picks this up with no code change - such accounts will now get their slot sensors. get_data() and all return types are unchanged (no breaking changes). The new weekly-deals helper (products.get_week_sales) and other 0.2.0 additions are intentionally not surfaced in the integration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqvRozwrnqt3NgyaYeBZe
Summary
Replaces the in-tree
RohlikCZAPIclient with the publishedrohlik-apiPyPI package and reworks the integration to consume the package's service-based API and typed models directly (no compatibility wrapper). Net ~920 lines deleted.What changed
rohlik-api==0.1.0.RohlikAPIdirectly:aiohttpsession per account (its own cookie jar → keeps multiple accounts isolated), lazy login, transparent 401 re-auth handled by the package;InvalidCredentialsError/RohlikAPIError→ConfigEntryAuthFailed/UpdateFailed;orders.get_all_delivered,orders.get_detail,products.get_categories);refresh_slotsviadelivery.get_next_slots; close the session on unload.RohlikAPI.login().Cartmodel (attribute access) instead of a dict.Cart,SearchResults,ShoppingList) to dicts only at the HA service-response boundary, so user-facing service response shapes are unchanged.rohlik_api.py(706 lines) anderrors.py.Compatibility
rohlik-apirequires Python ≥ 3.13, which Home Assistant mandates from 2025.2. This PR bumps the HACS minimum (hacs.json) and the README badge to2025.2so installs can't land on a 3.12 runtime where the dependency would fail to install.Testing
🤖 Generated with Claude Code
Generated by Claude Code