fix(LondonBoroughCamdenCouncil): rewrite for new waste portal API#2052
fix(LondonBoroughCamdenCouncil): rewrite for new waste portal API#2052InertiaUK wants to merge 1 commit into
Conversation
Camden migrated from environmentservices.camden.gov.uk (server-rendered HTML tables) to recyclingandrubbishcollections.camden.gov.uk (Next.js SPA with JSON API). Rewrote as pure requests: POST /api/getPropertySearch (postcode lookup to resolve property ID from UPRN) then POST /api/getCollectionDays (pointId + pointType PointAddress, councilId 27). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
📝 WalkthroughWalkthroughCamden Council's bin collection module transitions from HTML page scraping using BeautifulSoup to calling the council's recycling API. It now defines API credentials, searches for properties by postcode with optional UPRN matching, fetches active service schedules, and returns upcoming collection dates sorted chronologically. ChangesCamden Council API Integration
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2052 +/- ##
=======================================
Coverage 86.67% 86.67%
=======================================
Files 9 9
Lines 1141 1141
=======================================
Hits 989 989
Misses 152 152 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@uk_bin_collection/uk_bin_collection/councils/LondonBoroughCamdenCouncil.py`:
- Around line 64-70: The loop over collection_data currently tolerates
missing/changed payloads by using permissive defaults; instead validate and fail
loudly: check that collection_data contains "activeServices" and that it's a
list, raise a ValueError if not; inside the loop assert each service has a
non-empty "serviceName" (don't default to "Unknown") and that "serviceSchedules"
is present and is a list, and for each schedule assert "currentScheduledDate"
exists and is a parseable date (raise an exception if missing/invalid). Update
the code around collection_data, activeServices, serviceName, serviceSchedules
and currentScheduledDate to perform these explicit validations and raise
descriptive exceptions rather than silently continuing.
- Around line 43-45: The code currently falls back to properties[0]["id"] when
point_id is falsy, which silently returns another address's data if an uprn was
supplied but not matched; instead, in the method where point_id, properties and
uprn are handled (LondonBoroughCamdenCouncil.py, symbols: point_id, properties,
uprn), remove the silent fallback and add an explicit failure: if an uprn was
provided and no matching property was found, raise a clear exception (e.g.,
ValueError) containing the uprn and a descriptive message; keep the existing
behavior of selecting properties[0]["id"] only when no uprn was supplied (if
that is intended), otherwise eliminate the fallback entirely per the review.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 97604f43-d3e4-4bb2-a608-2c808042f937
📒 Files selected for processing (1)
uk_bin_collection/uk_bin_collection/councils/LondonBoroughCamdenCouncil.py
| # Fallback: first property if UPRN not matched | ||
| if not point_id: | ||
| point_id = properties[0]["id"] |
There was a problem hiding this comment.
Fail on UPRN mismatch instead of falling back to the first property.
At Line 44, defaulting to properties[0]["id"] can return another address’s collection data when uprn is provided but not found.
Suggested fix
- # Fallback: first property if UPRN not matched
- if not point_id:
- point_id = properties[0]["id"]
+ if not point_id:
+ raise ValueError(
+ f"UPRN {user_uprn} not found for postcode: {user_postcode}"
+ )Based on learnings: “prefer explicit failures (raise exceptions on unexpected formats) over silent defaults or swallowed errors.”
🤖 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 `@uk_bin_collection/uk_bin_collection/councils/LondonBoroughCamdenCouncil.py`
around lines 43 - 45, The code currently falls back to properties[0]["id"] when
point_id is falsy, which silently returns another address's data if an uprn was
supplied but not matched; instead, in the method where point_id, properties and
uprn are handled (LondonBoroughCamdenCouncil.py, symbols: point_id, properties,
uprn), remove the silent fallback and add an explicit failure: if an uprn was
provided and no matching property was found, raise a clear exception (e.g.,
ValueError) containing the uprn and a descriptive message; keep the existing
behavior of selecting properties[0]["id"] only when no uprn was supplied (if
that is intended), otherwise eliminate the fallback entirely per the review.
| for service in collection_data.get("activeServices", []): | ||
| bin_type = service.get("serviceName", "Unknown") | ||
|
|
||
| for schedule in service.get("serviceSchedules", []): | ||
| date_str = schedule.get("currentScheduledDate") | ||
| if not date_str: | ||
| continue |
There was a problem hiding this comment.
Avoid silent defaults when parsing activeServices payload fields.
Using permissive defaults (activeServices -> [], serviceName -> "Unknown", silently skipping missing dates) can mask upstream API changes and produce misleading empty/partial output.
Suggested fix
- for service in collection_data.get("activeServices", []):
- bin_type = service.get("serviceName", "Unknown")
+ active_services = collection_data.get("activeServices")
+ if not isinstance(active_services, list):
+ raise ValueError("Unexpected collection response: missing/invalid activeServices")
+
+ for service in active_services:
+ if "serviceName" not in service:
+ raise ValueError("Unexpected collection response: missing serviceName")
+ bin_type = service["serviceName"]Based on learnings: “prefer explicit failures (raise exceptions on unexpected formats) over silent defaults or swallowed errors.”
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| for service in collection_data.get("activeServices", []): | |
| bin_type = service.get("serviceName", "Unknown") | |
| for schedule in service.get("serviceSchedules", []): | |
| date_str = schedule.get("currentScheduledDate") | |
| if not date_str: | |
| continue | |
| active_services = collection_data.get("activeServices") | |
| if not isinstance(active_services, list): | |
| raise ValueError("Unexpected collection response: missing/invalid activeServices") | |
| for service in active_services: | |
| if "serviceName" not in service: | |
| raise ValueError("Unexpected collection response: missing serviceName") | |
| bin_type = service["serviceName"] | |
| for schedule in service.get("serviceSchedules", []): | |
| date_str = schedule.get("currentScheduledDate") | |
| if not date_str: | |
| continue |
🤖 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 `@uk_bin_collection/uk_bin_collection/councils/LondonBoroughCamdenCouncil.py`
around lines 64 - 70, The loop over collection_data currently tolerates
missing/changed payloads by using permissive defaults; instead validate and fail
loudly: check that collection_data contains "activeServices" and that it's a
list, raise a ValueError if not; inside the loop assert each service has a
non-empty "serviceName" (don't default to "Unknown") and that "serviceSchedules"
is present and is a list, and for each schedule assert "currentScheduledDate"
exists and is a parseable date (raise an exception if missing/invalid). Update
the code around collection_data, activeServices, serviceName, serviceSchedules
and currentScheduledDate to perform these explicit validations and raise
descriptive exceptions rather than silently continuing.
Summary
environmentservices.camden.gov.uk(server-rendered HTML) torecyclingandrubbishcollections.camden.gov.uk(Next.js SPA with JSON API)service-wrapperdivs which no longer existPOST /api/getPropertySearchwith postcode to resolve property ID from UPRNPOST /api/getCollectionDayswith pointId/pointType/councilId to get schedulesSummary by CodeRabbit