Skip to content

feat: SheffieldCityCouncil - add postcode + house number lookup#2060

Open
InertiaUK wants to merge 2 commits into
robbrad:masterfrom
InertiaUK:feat/sheffield-postcode-lookup
Open

feat: SheffieldCityCouncil - add postcode + house number lookup#2060
InertiaUK wants to merge 2 commits into
robbrad:masterfrom
InertiaUK:feat/sheffield-postcode-lookup

Conversation

@InertiaUK
Copy link
Copy Markdown
Contributor

@InertiaUK InertiaUK commented May 12, 2026

Summary

  • UPRN is no longer required for Sheffield. The scraper now accepts postcode + house number/name (paon) as an alternative.
  • Uses the existing getPropertySearch API to search by postcode, then matches the property by house number/name.
  • Falls back to first result if no match found.
  • Backward compatible: existing UPRN-based lookups continue to work unchanged.

Testing

  • Tested with UPRN (backward compat): S7 1RY + UPRN 100050931898
  • Tested with postcode + house number: S7 1RY + paon 22
  • Tested via API end-to-end

Summary by CodeRabbit

  • Bug Fixes

    • Sheffield bin lookups now use the council's official service for postcode/house-number searches, improving reliability and returning accurate upcoming collection days.
  • Chores

    • Input configuration updated to prioritize postcode and house number (UPRN accepted but optional) for Sheffield lookups.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Warning

Review limit reached

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

Your plan currently allows 2 reviews/hour. Refill in 23 minutes and 12 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd96daba-b680-4743-a5d3-b1363c72dd99

📥 Commits

Reviewing files that changed from the base of the PR and between 88dbdc7 and 38963b8.

📒 Files selected for processing (1)
  • uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py
📝 Walkthrough

Walkthrough

Migrates Sheffield council bin collection from HTML scraping to Sheffield Waste Services API: searches properties by postcode, matches by UPRN/PAON for pointId, fetches collection days, filters out completed services, formats scheduled dates, sorts them, and returns {"bins": [...]}.

Changes

Sheffield API Migration

Layer / File(s) Summary
API setup and dependencies
uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py
Swapped BeautifulSoup HTML parsing dependency for requests. Introduced API_BASE and COUNCIL_ID constants for Sheffield Waste Services endpoints.
Property matching utility
uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py
Added _match_property(properties, uprn=None, paon=None) that selects a property by UPRN exact match, then PAON substring match, falling back to the first result.
Schedule retrieval and parsing
uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py
Rewrote CouncilClass.parse_data() to call getPropertySearch and getCollectionDays, validate postcode, obtain pointId, skip schedules with state "Complete", parse scheduled dates from currentScheduledDate or originalScheduledDate, format them with date_format, and return sorted bin entries in {"bins": [...]}.
Input configuration update
uk_bin_collection/tests/input.json
Updated SheffieldCityCouncil test input to use postcode and house_number; uprn accepted but not required and previous property-specific wiki_command_url_override removed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped from soup to tidy API streams,
Postcodes hum and pointIds gleam,
Dates parsed neat from current or old,
Bins lined up, in order told,
Happy hops — the schedule's clean!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: SheffieldCityCouncil - add postcode + house number lookup' accurately describes the main change: adding postcode and house number lookup capability to the Sheffield Council scraper, replacing the previous UPRN-only requirement.
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
Contributor

@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

🤖 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/SheffieldCityCouncil.py`:
- Around line 94-95: In the schedule date parsing block inside the
SheffieldCityCouncil scraper (class SheffieldCityCouncil), stop silently
swallowing ValueError/TypeError; instead capture the original exception and
re-raise (or raise a new descriptive exception) including the offending date
string and context so upstream callers see the failure; if you have a logger
(e.g. self.logger or module logger) emit an error with the raw value before
raising to aid debugging.
- Around line 24-27: The loop over properties is doing fuzzy substring matching
via "if paon_norm in name" which causes wrong matches (e.g., "2" matching "22");
change this to exact PAON equality by replacing that condition with an exact
comparison (e.g., compare the normalized name to paon_norm using ==) so the code
returns prop["id"] only on an exact PAON match; keep the existing normalization
(str(...).upper()) and leave the later fallback behavior intact.
🪄 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: 3b86f3f0-0ee4-4bad-a416-7e0c709f3a10

📥 Commits

Reviewing files that changed from the base of the PR and between 8ecf878 and 563fbdf.

📒 Files selected for processing (1)
  • uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py

Comment on lines +94 to +95
except (ValueError, TypeError):
continue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t silently swallow schedule date parsing failures.

Catching parse errors and continue-ing hides upstream API format changes and can return partial/incorrect data without any signal.

Suggested fix
-                except (ValueError, TypeError):
-                    continue
+                except (ValueError, TypeError) as exc:
+                    raise ValueError(
+                        f"Unexpected schedule date format for service '{bin_type}': {date_str!r}"
+                    ) from exc

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.

Suggested change
except (ValueError, TypeError):
continue
except (ValueError, TypeError) as exc:
raise ValueError(
f"Unexpected schedule date format for service '{bin_type}': {date_str!r}"
) from exc
🤖 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/SheffieldCityCouncil.py` around
lines 94 - 95, In the schedule date parsing block inside the
SheffieldCityCouncil scraper (class SheffieldCityCouncil), stop silently
swallowing ValueError/TypeError; instead capture the original exception and
re-raise (or raise a new descriptive exception) including the offending date
string and context so upstream callers see the failure; if you have a logger
(e.g. self.logger or module logger) emit an error with the raw value before
raising to aid debugging.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.67%. Comparing base (8ecf878) to head (38963b8).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2060   +/-   ##
=======================================
  Coverage   86.67%   86.67%           
=======================================
  Files           9        9           
  Lines        1141     1141           
=======================================
  Hits          989      989           
  Misses        152      152           

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

Copy link
Copy Markdown
Contributor

@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

🤖 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/tests/input.json`:
- Line 2137: The "wiki_note" string for the entry currently mentions only "house
number" but the parser accepts house numbers or house names (PAON); update the
value of the "wiki_note" JSON field to explicitly say "house number or house
name (PAON)" and mention that UPRN is accepted but not required so the note
covers named properties as well; locate the JSON entry with the "wiki_note" key
(and related "house_number"/"PAON" semantics) and replace the wording
accordingly.
- Around line 2131-2133: The fixture currently includes both "uprn" and
"house_number", so _match_property() in SheffieldCityCouncil.py will always take
the UPRN branch and never exercise the postcode+house_number (paon) lookup; fix
by splitting into two fixtures (or duplicate this fixture): one retaining "uprn"
to test the UPRN path and a second that removes the "uprn" field but keeps
"postcode" and "house_number" to test the paon/postcode lookup, ensuring both
lookup branches are covered by tests.
🪄 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: e7099e49-1292-4c12-94bd-11433c002dfb

📥 Commits

Reviewing files that changed from the base of the PR and between 563fbdf and 924afd2.

📒 Files selected for processing (1)
  • uk_bin_collection/tests/input.json

Comment on lines +2131 to +2133
"postcode": "S7 1RY",
"uprn": "100050931898",
"house_number": "22",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Locate Sheffield scraper and input fixture"
fd -i "SheffieldCityCouncil.py"
fd -i "input.json"

echo
echo "2) Inspect lookup precedence in Sheffield scraper"
rg -n -C3 --type=py '\buprn\b|\bpostcode\b|\bhouse_number\b|\bpaon\b' uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py

echo
echo "3) Inspect how tests map fields from input.json into scraper arguments"
rg -n -C3 --type=py 'tests/input\.json|input\.json|uprn|postcode|house_number|paon' uk_bin_collection

Repository: robbrad/UKBinCollectionData

Length of output: 50384


🏁 Script executed:

rg -A5 -B5 'SheffieldCityCouncil' uk_bin_collection/tests/input.json | head -80

Repository: robbrad/UKBinCollectionData

Length of output: 554


Separate fixtures needed to test both UPRN and postcode+house_number lookup paths.

With both uprn and house_number present, the _match_property() function checks uprn first (line 13 of SheffieldCityCouncil.py) and returns immediately on match, never reaching the paon matching logic. This fixture only exercises the UPRN path and doesn't test the postcode+house_number path. Split into two fixtures or remove uprn from this one to ensure coverage of both lookup methods.

🤖 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/tests/input.json` around lines 2131 - 2133, The fixture
currently includes both "uprn" and "house_number", so _match_property() in
SheffieldCityCouncil.py will always take the UPRN branch and never exercise the
postcode+house_number (paon) lookup; fix by splitting into two fixtures (or
duplicate this fixture): one retaining "uprn" to test the UPRN path and a second
that removes the "uprn" field but keeps "postcode" and "house_number" to test
the paon/postcode lookup, ensuring both lookup branches are covered by tests.

"url": "https://wasteservices.sheffield.gov.uk",
"wiki_name": "Sheffield",
"wiki_note": "Follow the instructions [here](https://wasteservices.sheffield.gov.uk/) until you get the 'Your bin collection dates and services' page, then copy the URL and replace the URL in the command.",
"wiki_note": "Provide your postcode and house number. UPRN is also accepted but no longer required.",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify that house_number also accepts house names (PAON).

Line 2137 currently says “house number”, but this parser now supports house number/name. Update the note to avoid excluding valid named properties.

✏️ Suggested wording update
-        "wiki_note": "Provide your postcode and house number. UPRN is also accepted but no longer required.",
+        "wiki_note": "Provide your postcode and house number/name (PAON). UPRN is also accepted but no longer required.",
📝 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.

Suggested change
"wiki_note": "Provide your postcode and house number. UPRN is also accepted but no longer required.",
"wiki_note": "Provide your postcode and house number/name (PAON). UPRN is also accepted but no longer required.",
🤖 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/tests/input.json` at line 2137, The "wiki_note" string for
the entry currently mentions only "house number" but the parser accepts house
numbers or house names (PAON); update the value of the "wiki_note" JSON field to
explicitly say "house number or house name (PAON)" and mention that UPRN is
accepted but not required so the note covers named properties as well; locate
the JSON entry with the "wiki_note" key (and related "house_number"/"PAON"
semantics) and replace the wording accordingly.

UPRN is no longer required. Users can provide postcode + house number
as an alternative. Uses getPropertySearch API to match by address.
Backward compatible - existing UPRN lookups still work.
@InertiaUK InertiaUK force-pushed the feat/sheffield-postcode-lookup branch from 924afd2 to 88dbdc7 Compare May 12, 2026 15:21
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