internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: Shropshire Council, UK
### Municipality / Region

Shropshire, UK

### Collection Calendar Webpage

https://bins.shropshire.gov.uk/

### Example Address

SY2 6PH

### Collection Data Format

As ICS/ICAL file, As html on a webpage, Something different (add to additional information)

### Additional Information

The URL seems to comprise of the UPRN, eg: https://bins.shropshire.gov.uk/property/100070034745

Also, when you go to the services page (eg: https://bins.shropshire.gov.uk/property/100070034745#services) there is also an ical download next to the next collection date.


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/shropshire_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/shropshire_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/shropshire_gov_uk.py
@@ -0,0 +1,70 @@
+# Credit where it's due:
+# This is predominantly a refactoring of the Bristol City Council script from the UKBinCollectionData repo
+# https://github.com/robbrad/UKBinCollectionData
+
+from datetime import datetime
+
+import requests
+from bs4 import BeautifulSoup
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "Shropshire Council"
+DESCRIPTION = "Source for Shropshire Council."
+URL = "https://shropshire.gov.uk"
+TEST_CASES = {
+    "100070056686": {"uprn": 100070056686},
+    "200000119191": {"uprn": "200000119191"},
+}
+
+
+ICON_MAP = {
+    "General": "mdi:trash-can",
+    "Garden": "mdi:leaf",
+    "Recycling": "mdi:recycle",
+}
+
+
+API_URL = "https://bins.shropshire.gov.uk/property/{uprn}"
+
+
+class Source:
+    def __init__(self, uprn: str | int):
+        self._uprn: str | int = uprn
+
+    def fetch(self):
+        page = requests.get(API_URL.format(uprn=self._uprn))
+        page.raise_for_status()
+
+        # Make a BS4 object
+        soup = BeautifulSoup(page.text, features="html.parser")
+        soup.prettify()
+
+        # Form a JSON wrapper
+        entries = []
+
+        # Find section with bins in
+        sections = (
+            soup.find("div", {"class": "container results-table-wrapper"})
+            .find("tbody")
+            .find_all("tr")
+        )
+
+        # For each bin section, get the text and the list elements
+        for item in sections:
+            words = item.find_next("a").text.split()[:-1]
+            bin_type = " ".join(words).capitalize()
+            date = (
+                item.find("td", {"class": "next-service"})
+                .find_next("span")
+                .next_sibling.strip()
+            )
+            next_collection = datetime.strptime(date, "%d/%m/%Y").date()
+            entries.append(
+                Collection(
+                    t=bin_type,
+                    date=next_collection,
+                    icon=ICON_MAP.get(bin_type.split(" ")[0].lower()),
+                )
+            )
+
+        return entries


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: Request for Selby
### Municipality / Region

Selby, North Yorks

### Collection Calendar Webpage

https://www.northyorks.gov.uk/bin-calendar/Selby/results/100052176620

### Example Address

UPRN: 10013454353

https://www.northyorks.gov.uk/bin-calendar/Selby/results/10013454353

### Collection Data Format

As html on a webpage

### Additional Information

_No response_


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/northyorks_selby_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/northyorks_selby_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/northyorks_selby_gov_uk.py
@@ -0,0 +1,66 @@
+from datetime import datetime
+
+import requests
+from bs4 import BeautifulSoup
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "North Yorkshire Council - Selby"
+DESCRIPTION = "Source for North Yorkshire Council - Selby."
+URL = "https://northyorks.gov.uk"
+TEST_CASES = {
+    "100052176620": {"uprn": 100052176620},
+    "10013454353": {"uprn": "10013454353"},
+}
+
+
+ICON_MAP = {
+    "Household": "mdi:trash-can",
+    "Garden": "mdi:leaf",
+    "Recycling": "mdi:recycle",
+}
+
+
+API_URL = "https://www.northyorks.gov.uk/bin-calendar/Selby/results/{uprn}/ajax?_wrapper_format=drupal_ajax"
+
+
+class Source:
+    def __init__(self, uprn: str | int):
+        self._uprn: str = str(uprn)
+
+    def fetch(self):
+        r = requests.post(API_URL.format(uprn=self._uprn))
+        r.raise_for_status()
+
+        html = None
+        for res in r.json():
+            if "data" in res and isinstance(res["data"], str):
+                html = res["data"]
+                break
+        if not html or "Unfortunately we were unable to find your property" in html:
+            raise Exception("No data found, invalid UPRN?")
+        soup = BeautifulSoup(html, "html.parser")
+
+        rows = (
+            soup.find("div", id="upcoming-collection")
+            .find("table")
+            .find("tbody")
+            .find_all("tr")
+        )
+
+        entries = []
+        for row in rows:
+            tds = row.find_all("td")
+
+            if not tds or len(tds) < 3:
+                continue
+            date_str = tds[0].text
+            date = datetime.strptime(date_str, "%d %B %Y").date()
+            bin_types = [br.next_sibling.strip() for br in tds[2].find_all("i")]
+            if not bin_types:
+                continue
+
+            for bin_type in bin_types:
+                icon = ICON_MAP.get(bin_type.split(" ")[0])
+                entries.append(Collection(date=date, t=bin_type, icon=icon))
+
+        return entries


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Bug]: "Ortsteil" missing for AbfallPlus in Weißenburg/Gunzenhausen
### I Have A Problem With:

A specific source

### What's Your Problem

For my part of the village (aka "Ortsteil") it is not choosable. 
You can check it here: https://www.landkreis-wug.de/abfall/abfuhrkalender/ , I have to select
Stadt/Gemeinde:Haundorf
Straße/Ortsteil: Obererlbach
Straße: Alle Straßen

I tried the app_abfallplus_de.py script, but I can't select my "Ortsteil", just the Maincommunity/-city "Haundorf".
waste_collection_schedule:
    sources:
    - name: app_abfallplus_de
      args:
        app_id: de.k4systems.abfallappwug
        city: Haundorf
        strasse: alle Straßen

### Source (if relevant)

app_abfallplus_de

### Logs

_No response_

### Relevant Configuration

_No response_

### Checklist Source Error

- [X] Use the example parameters for your source (often available in the documentation) (don't forget to restart Home Assistant after changing the configuration)
- [X] Checked that the website of your service provider is still working
- [X] Tested my attributes on the service provider website (if possible)
- [X] I have tested with the latest version of the integration (master) (for HACS in the 3 dot menu of the integration click on "Redownload" and choose master as version)

### Checklist Sensor Error

- [X] Checked in the Home Assistant Calendar tab if the event names match the types names (if types argument is used)

### Required

- [X] I have searched past (closed AND opened) issues to see if this bug has already been reported, and it hasn't been.
- [X] I understand that people give their precious time for free, and thus I've done my very best to make this problem as easy as possible to investigate.


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/wizard/app_abfallplus_de.py b/custom_components/waste_collection_schedule/waste_collection_schedule/wizard/app_abfallplus_de.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/wizard/app_abfallplus_de.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/wizard/app_abfallplus_de.py
@@ -168,7 +168,7 @@ def main():
     app_id = inquirer.prompt(questions)["app-id"]
 
     app = AppAbfallplusDe.AppAbfallplusDe(app_id, "", "", "")
-    bezirk_needed = "bezirk" in app.init_connection() and app.get_bezirke() != []
+    bezirk_needed = "bezirk" in app.init_connection()
     cities = app.get_kommunen()
     bund_select = cities == []
 
@@ -182,6 +182,7 @@ def main():
     finished = False
     house_number = ""
     street = None
+    bezirk_needed = bezirk_needed and app.get_bezirke() != []
     if bezirk_needed:
         bezirk, finished = select_bezirk(app, bund_select)
     if not finished:


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Bug]: fetch failed for source Stavanger Kommune
### I Have A Problem With:

A specific source

### What's Your Problem

Unable to fetch data for Stavanger Norway. Have worked flawless a while, but no there is no data.

### Source (if relevant)

stavanger_no

### Logs

```Shell
This error originated from a custom integration.

Logger: waste_collection_schedule.source_shell
Source: custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py:136
Integration: waste_collection_schedule (documentation)
First occurred: 11:08:21 (2 occurrences)
Last logged: 11:13:26

fetch failed for source Stavanger Kommune: Traceback (most recent call last): File "/config/custom_components/waste_collection_schedule/waste_collection_schedule/source_shell.py", line 134, in fetch entries = self._source.fetch() ^^^^^^^^^^^^^^^^^^^^ File "/config/custom_components/waste_collection_schedule/waste_collection_schedule/source/stavanger_no.py", line 49, in fetch r.raise_for_status() File "/usr/local/lib/python3.12/site-packages/requests/models.py", line 1021, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 500 Server Error: Internal Server Error for url: https://www.stavanger.kommune.no/renovasjon-og-miljo/tommekalender/finn-kalender/show?id=###removed###
```


### Relevant Configuration

_No response_

### Checklist Source Error

- [X] Use the example parameters for your source (often available in the documentation) (don't forget to restart Home Assistant after changing the configuration)
- [X] Checked that the website of your service provider is still working
- [X] Tested my attributes on the service provider website (if possible)
- [X] I have tested with the latest version of the integration (master) (for HACS in the 3 dot menu of the integration click on "Redownload" and choose master as version)

### Checklist Sensor Error

- [X] Checked in the Home Assistant Calendar tab if the event names match the types names (if types argument is used)

### Required

- [X] I have searched past (closed AND opened) issues to see if this bug has already been reported, and it hasn't been.
- [X] I understand that people give their precious time for free, and thus I've done my very best to make this problem as easy as possible to investigate.


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/stavanger_no.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/stavanger_no.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/stavanger_no.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/stavanger_no.py
@@ -38,6 +38,7 @@ def fetch(self):
         headers = {"referer": "https://www.stavanger.kommune.no"}
 
         params = {
+            "ids": self._id,
             "id": self._id,
             "municipality": self._municipality,
             "gnumber": self._gnumber,


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: Flintshire, United Kingdom
### Municipality / Region

Flintshire, United Kingdom

### Collection Calendar Webpage

https://digital.flintshire.gov.uk/FCC_BinDay

### Example Address

7 Drury Lane, BUCKLEY, CH7 3JD 

### Collection Data Format

As html on a webpage

### Additional Information

_No response_


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/flintshire_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/flintshire_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/flintshire_gov_uk.py
@@ -0,0 +1,60 @@
+import re
+from datetime import datetime
+
+import requests
+from bs4 import BeautifulSoup
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "Flintshire"
+DESCRIPTION = "Source for Flintshire, United Kingdom."
+URL = "https://flintshire.gov.uk/"
+TEST_CASES = {
+    "100100211557": {"uprn": 100100211557},
+    "200001744973": {"uprn": "200001744973"},
+}
+
+
+ICON_MAP = {
+    "Trash": "mdi:trash-can",
+    "Glass": "mdi:bottle-soda",
+    "Bio": "mdi:leaf",
+    "Paper": "mdi:package-variant",
+    "Recycle": "mdi:recycle",
+}
+
+
+API_URL = "https://digital.flintshire.gov.uk/FCC_BinDay/Home/Details2/{UPRN}"
+
+
+class Source:
+    def __init__(self, uprn: str | int):
+        self._url = API_URL.format(UPRN=uprn)
+
+    def fetch(self):
+        r = requests.post(self._url)
+        if r.status_code == 500:
+            raise Exception("web request failed: probably caused by an invalid UPRN")
+        r.raise_for_status()
+
+        soup = BeautifulSoup(r.text, "html.parser")
+
+        rows = soup.find_all("div", class_="col-md-12")
+        entries = []
+
+        for row in rows:
+            cols = row.find_all("div")
+            cols = list(map(lambda x: x.text.strip(), cols))
+            if len(cols) == 0 or not re.match(r"\d{2}/\d{2}/\d{4}", cols[0]):
+                print("Skipping row", row.find("div"))
+                continue
+            date_str = cols[0]
+            date = datetime.strptime(date_str, "%d/%m/%Y").date()
+
+            waste_types = cols[2].split("/")
+
+            for waste_type in waste_types:
+                icon = ICON_MAP.get(waste_type.lower().strip())  # Collection icon
+                type = waste_type.strip()
+                entries.append(Collection(date=date, t=type, icon=icon))
+
+        return entries


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: UK - Eastleigh
### Municipality / Region

Eastleigh, England, UK

### Collection Calendar Webpage

https://www.eastleigh.gov.uk/waste-bins-and-recycling/collection-dates

### Example Address

https://www.eastleigh.gov.uk/waste-bins-and-recycling/collection-dates/your-waste-bin-and-recycling-collections?uprn=100060319000

### Collection Data Format

As html on a webpage, As PDF Download

### Additional Information

There are 5 different dates available for differing collections:
Household Waste Bin
Recycling Bin
Food Waste Bin
Glass Box and Batteries
Garden Waste Bin


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/eastleigh_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/eastleigh_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/eastleigh_gov_uk.py
@@ -0,0 +1,64 @@
+from datetime import datetime
+
+import requests
+from bs4 import BeautifulSoup
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "Eastleigh Borough Council"
+DESCRIPTION = "Source for Eastleigh Borough Council."
+URL = "https://eastleigh.gov.uk"
+TEST_CASES = {
+    "100060319000": {"uprn": 100060319000},
+    "100060300958": {"uprn": "100060300958"},
+}
+
+
+ICON_MAP = {
+    "Paper": "mdi:package-variant",
+    "household": "mdi:trash-can",
+    "recycling": "mdi:recycle",
+    "food": "mdi:food",
+    "glass": "mdi:bottle-soda",
+    "garden": "mdi:leaf",
+}
+
+
+API_URL = "https://eastleigh.gov.uk/waste-bins-and-recycling/collection-dates/your-waste-bin-and-recycling-collections"
+
+
+class Source:
+    def __init__(self, uprn: str | int):
+        self._uprn: str | int = uprn
+
+    def fetch(self):
+        args = {"uprn": self._uprn}
+
+        # get json file
+        r = requests.get(API_URL, params=args)
+        r.raise_for_status()
+
+        soup = BeautifulSoup(r.text, "html.parser")
+        dls = soup.find_all("dl")
+
+        entries = []
+
+        for dl in dls:
+            dts = dl.findAll("dt")
+            for dt in dts:
+                dd = dt.find_next_sibling("dd")
+                if not dd:
+                    continue
+
+                try:
+                    # Mon, 29 Apr 2024
+                    date = datetime.strptime(dd.text, "%a, %d %b %Y").date()
+                except ValueError:
+                    continue
+
+                icon = ICON_MAP.get(
+                    dt.text.strip().split(" ")[0].lower()
+                )  # Collection icon
+                type = dt.text
+                entries.append(Collection(date=date, t=type, icon=icon))
+
+        return entries


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: Sutton Council, London
### Municipality / Region

Sutton, London

### Collection Calendar Webpage

https://waste-services.sutton.gov.uk/waste

### Example Address

8 thread street, sm67fb

### Collection Data Format

As html on a webpage

### Additional Information

_No response_


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/ics.py
@@ -195,6 +195,7 @@ def fetch_url(self, url, params=None):
             raise RuntimeError(
                 "Error: unknown method to fetch URL, use GET or POST; got {self._method}"
             )
+        print(r.text)
         r.raise_for_status()
 
         if r.apparent_encoding == "UTF-8-SIG":
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/sutton_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/sutton_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/sutton_gov_uk.py
@@ -0,0 +1,51 @@
+from time import sleep
+
+import requests
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+from waste_collection_schedule.service.ICS import ICS
+
+TITLE = "Sutton Council, London"
+DESCRIPTION = "Source for Sutton Council, London."
+URL = "https://sutton.gov.uk"
+TEST_CASES = {"4721996": {"id": 4721996}, "4499298": {"id": "4499298"}}
+
+
+ICON_MAP = {
+    "non-recyclable": "mdi:trash-can",
+    "paper": "mdi:package-variant",
+    "mixed": "mdi:recycle",
+    "food": "mdi:food",
+}
+
+
+API_URL = "https://waste-services.sutton.gov.uk/waste/{id}"
+ICAL_URL = API_URL + "/calendar.ics"
+
+
+class Source:
+    def __init__(self, id: str | int):
+        self._id: str | int = id
+        self._ics = ICS()
+
+    def fetch(self):
+        s = requests.Session()
+        api_url = API_URL.format(id=self._id)
+        ical_url = ICAL_URL.format(id=self._id)
+
+        r = s.get(api_url)
+        while f'hx-get="/waste/{self._id}"' in r.text:
+            sleep(2)
+            r = s.get(api_url)
+        r.raise_for_status()
+
+        r = s.get(ical_url)
+        r.raise_for_status()
+
+        dates = self._ics.convert(r.text)
+        entries = []
+        for d in dates:
+            entries.append(
+                Collection(d[0], d[1], ICON_MAP.get(d[1].split(" ")[0].lower()))
+            )
+
+        return entries


Test patch:
Repository: mampfes/hacs_waste_collection_schedule

Issue:
[Source Request]: West Northants
### Municipality / Region

West Nothants, UK

### Collection Calendar Webpage

https://www.westnorthants.gov.uk/bin-collection-services/bin-collection-day

### Example Address

NN7 4PZ, any address will provide data

### Collection Data Format

As html on a webpage

### Additional Information

Site is identical to the recently added north northants source


Discussion:

Resolving patch:
diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/westnorthants_gov_uk.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/westnorthants_gov_uk.py
new file mode 100644
--- /dev/null
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/westnorthants_gov_uk.py
@@ -0,0 +1,54 @@
+from datetime import datetime
+
+import requests
+from waste_collection_schedule import Collection  # type: ignore[attr-defined]
+
+TITLE = "West Northamptonshire council"
+DESCRIPTION = "Source for West Northamptonshire council."
+URL = "https://www.westnorthants.gov.uk/"
+TEST_CASES = {
+    "28058314": {"uprn": 28058314},
+    "15049111": {"uprn": "15049111"},
+}
+
+
+ICON_MAP = {
+    "refuse": "mdi:trash-can",
+    "food": "mdi:food",
+    "garden": "mdi:recycle",
+    "recycling": "mdi:package-variant",
+    "recycling_boxes": "mdi:package-variant",
+    "sacks": "mdi:sack",
+}
+
+
+API_URL = (
+    "https://api.westnorthants.digital/openapi/v1/unified-waste-collections/{uprn}"
+)
+
+
+class Source:
+    def __init__(self, uprn: str | int):
+        self._uprn: str | int = uprn
+
+    def fetch(self):
+        # Get variables for workings
+        response = requests.get(
+            API_URL.format(uprn=self._uprn),
+        )
+        response.raise_for_status()
+        data = response.json()
+
+        entries = []
+
+        for collection in data["collectionItems"]:
+            day = datetime.strptime(collection["date"], "%Y-%m-%d").date()
+            entries.append(
+                Collection(
+                    t=collection["type"],
+                    date=day,
+                    icon=ICON_MAP.get(collection["type"]),
+                )
+            )
+
+        return sorted(entries, key=lambda x: x.date)


Test patch: