We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[Bug]: portenf_sa_gov_au reporting incorrect dates
### I Have A Problem With:

A specific source

### What's Your Problem

The portenf_sa_gov_au sensor has been reporting incorrectly since it updated itself on 24 December 2023 (I can see this from HA logs). It appears that when there is 1 week or less left in the month "main-month" switches to the coming month and "other-month" becomes the current month.

Because of this, the integration reports the current collection next month and the next collections as in the past (and hides them).

The fix in #1110 by @5ila5 partly addresses the problem but it was not foreseeable to him that EOM would be treated this way. @5ila5 also noted that this might be an issue in that closed issue.

### Source (if relevant)

portenf_sa_gov_au

### Logs

```Shell
Output of test_sources.py:

Testing source portenf_sa_gov_au ...
  found 8 entries for Broadview, Regency Road, 565
    2024-01-26 : general-waste bin [mdi:trash-can]
    2024-01-26 : recycling bin [mdi:recycle]
    2023-12-02 : general-waste bin [mdi:trash-can]
    2023-12-02 : organics bin [mdi:leaf]
    2023-12-09 : general-waste bin [mdi:trash-can]
    2023-12-09 : recycling bin [mdi:recycle]
    2023-12-16 : general-waste bin [mdi:trash-can]
    2023-12-16 : organics bin [mdi:leaf]
  found 8 entries for 48 Floriedale Rd
    2024-01-26 : general-waste bin [mdi:trash-can]
    2024-01-26 : recycling bin [mdi:recycle]
    2023-12-02 : general-waste bin [mdi:trash-can]
    2023-12-02 : organics bin [mdi:leaf]
    2023-12-09 : general-waste bin [mdi:trash-can]
    2023-12-09 : recycling bin [mdi:recycle]
    2023-12-16 : general-waste bin [mdi:trash-can]
    2023-12-16 : organics bin [mdi:leaf]
  found 8 entries for 24 Margaret Terrace
    2024-01-28 : general-waste bin [mdi:trash-can]
    2024-01-28 : organics bin [mdi:leaf]
    2023-12-04 : general-waste bin [mdi:trash-can]
    2023-12-04 : recycling bin [mdi:recycle]
    2023-12-11 : general-waste bin [mdi:trash-can]
    2023-12-11 : organics bin [mdi:leaf]
    2023-12-18 : general-waste bin [mdi:trash-can]
    2023-12-18 : recycling bin [mdi:recycle]
  found 8 entries for Addison Road 91 with unit
    2024-01-28 : general-waste bin [mdi:trash-can]
    2024-01-28 : organics bin [mdi:leaf]
    2023-12-04 : general-waste bin [mdi:trash-can]
    2023-12-04 : recycling bin [mdi:recycle]
    2023-12-11 : general-waste bin [mdi:trash-can]
    2023-12-11 : organics bin [mdi:leaf]
    2023-12-18 : general-waste bin [mdi:trash-can]
    2023-12-18 : recycling bin [mdi:recycle]
```


### 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.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py`
Content:
```
1 import datetime
2 import logging
3 import re
4 
5 import requests
6 import urllib3
7 from bs4 import BeautifulSoup
8 from waste_collection_schedule import Collection  # type: ignore[attr-defined]
9 
10 # With verify=True the POST fails due to a SSLCertVerificationError.
11 # Using verify=False works, but is not ideal. The following links may provide a better way of dealing with this:
12 # https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
13 # https://urllib3.readthedocs.io/en/1.26.x/user-guide.html#ssl
14 # These two lines areused to suppress the InsecureRequestWarning when using verify=False
15 urllib3.disable_warnings()
16 
17 TITLE = "Port Adelaide Enfield, South Australia"
18 DESCRIPTION = "Source for City of Port Adelaide Enfield, South Australia."
19 URL = "https://ecouncil.portenf.sa.gov.au/"
20 TEST_CASES = {
21     "Broadview, Regency Road, 565 ": {
22         "suburb": "Broadview",
23         "street": "Regency Road",
24         "house_number": 565,
25         "unit_number": "",
26     },
27     "48 Floriedale Rd ": {
28         "suburb": "Greenacres",
29         "street": "Floriedale Rd",
30         "house_number": "48",
31     },
32     "24 Margaret Terrace": {
33         "suburb": "Rosewater",
34         "street": "Margaret Terrace",
35         "house_number": "24",
36     },
37     "Addison Road 91 with unit": {
38         "suburb": "Rosewater",
39         "street": "Addison Road",
40         "house_number": 91,
41         "unit_number": 2,
42     },
43 }
44 
45 ICON_MAP = {
46     "general-waste bin": "mdi:trash-can",
47     "organics bin": "mdi:leaf",
48     "recycling bin": "mdi:recycle",
49 }
50 
51 LOGGER = logging.getLogger(__name__)
52 
53 API_URL = "https://ecouncil.portenf.sa.gov.au/public/propertywastedates/public.aspx"
54 
55 
56 class Source:
57     def __init__(
58         self,
59         suburb: str,
60         street: str,
61         house_number: str | int,
62         unit_number: str | int = "",
63     ):
64         self._suburb: str = suburb
65         self._street: str = street
66         self._house_number: str = str(house_number)
67         self._unit_number: str = str(unit_number)
68 
69     def __set_args(
70         self, soup: BeautifulSoup, event_taget=None, additional: dict = {}
71     ) -> dict:
72         args = {
73             "ctl00$MainContent$txtSuburb": self._suburb,
74             "ctl00$MainContent$txtStreetName": self._street,
75             "ctl00$MainContent$txtHouseNumber": self._house_number,
76             "ctl00$MainContent$txtUnitNumber": self._unit_number,
77         }
78         if event_taget is not None:
79             args["__EVENTTARGET"] = event_taget
80 
81         for hidden_val in soup.find_all("input", {"type": "hidden"}):
82             args[hidden_val["name"]] = hidden_val["value"]
83 
84         for key, value in additional.items():
85             args[key] = value
86         return args
87 
88     def fetch(self):
89         session = requests.Session()
90 
91         # get First page
92         r = session.get(API_URL, verify=False)
93         r.raise_for_status()
94 
95         # extractt arguments
96         args = self.__set_args(
97             BeautifulSoup(r.text, "html.parser"),
98             event_taget="ctl00$MainContent$btnSearch",
99         )
100 
101         r = session.post(API_URL, data=args)
102         r.raise_for_status()
103 
104         # get page to select an address
105         soup = BeautifulSoup(r.text, "html.parser")
106 
107         selectable = soup.find_all("a", {"class": "anchor-button small"}, text="Select")
108 
109         if len(selectable) == 0:
110             raise ValueError("No address found")
111         selected = selectable[0]
112 
113         # If multiple addresses are found, try to find the one that matches the input and warn if there are multiple or none matches
114         if len(selectable) > 1:
115             found = [
116                 " ".join(
117                     [y.text for y in x.parent.parent.find_all("td")[1].find_all("span")]
118                 )
119                 for x in selectable
120             ]
121             using_index = 0
122 
123             match = False
124 
125             for index, entry in enumerate(found):
126                 entry = entry.lower().strip().replace("  ", "")
127                 if (
128                     self._house_number.lower().strip().replace("  ", "") in entry
129                     and self._street.lower().strip().replace("  ", "") in entry
130                     and self._suburb.lower().strip().replace("  ", "") in entry
131                     and self._unit_number.lower().strip().replace("  ", "") in entry
132                 ):
133                     if match:
134                         LOGGER.warning(
135                             f"Multiple addresses found, using first one \nfound:{', '.join(found[:10])}{'...' if len(found) >= 10 else ''} \nusing:{found[using_index]}"
136                         )
137                         break
138                     using_index = index
139                     match = True
140             if not match:
141                 LOGGER.warning(
142                     f"no perfect address match found, using:{found[using_index]}"
143                 )
144 
145         # request first address
146         args = self.__set_args(
147             soup,
148             event_taget="ctl00$MainContent$gvPropertyResults$ctl02$btnSelect",
149             additional={selected["href"].split("'")[1]: ""},
150         )
151         r = session.post(API_URL, data=args)
152         r.raise_for_status()
153 
154         soup = BeautifulSoup(r.text, "html.parser")
155         cal_header = soup.find("th", {"class": "header-month"}).find("span").text
156         main_month = cal_header.split("-")[0].strip()
157 
158         secondary_month = cal_header.split("-")[1].strip().split(" ")[0]
159         secondary_year = main_year = cal_header.split("-")[1].strip().split(" ")[1]
160 
161         # if main month contains a year, set it (maybe happens in december???)
162         if len(main_month.split(" ")) > 1:
163             main_year = main_month.split(" ")[1]
164             main_month = main_month.split(" ")[0]
165 
166         entries = []
167 
168         calendar = soup.find("table", {"class": "collection-day-calendar"})
169         # Iterate over all days with pickups
170         for pickup in calendar.find_all(
171             "div", {"class": re.compile(r"pickup|next-pickup")}
172         ):
173             parent_td = pickup.parent
174             month = (
175                 main_month
176                 if "main-month" in parent_td.attrs["class"]
177                 else secondary_month
178             )
179             year = (
180                 main_year
181                 if "main-month" in parent_td.attrs["class"]
182                 else secondary_year
183             )
184             day = parent_td.find("div", {"class": "daynumber"}).text
185 
186             # Iterate over all pickup container types for this day
187             for container in pickup.find_all("div", {"class": "bin-container"}):
188                 container_type = " ".join(container.find("div").attrs["class"])
189                 container_icon = ICON_MAP.get(container_type)
190 
191                 date = datetime.datetime.strptime(
192                     f"{year}-{month}-{day}", "%Y-%B-%d"
193                 ).date()
194                 entries.append(
195                     Collection(date=date, t=container_type, icon=container_icon)
196                 )
197 
198         return entries
199
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py
--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py
+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py
@@ -1,6 +1,6 @@
-import datetime
 import logging
 import re
+from datetime import datetime
 
 import requests
 import urllib3
@@ -153,15 +153,28 @@
 
         soup = BeautifulSoup(r.text, "html.parser")
         cal_header = soup.find("th", {"class": "header-month"}).find("span").text
-        main_month = cal_header.split("-")[0].strip()
-
-        secondary_month = cal_header.split("-")[1].strip().split(" ")[0]
-        secondary_year = main_year = cal_header.split("-")[1].strip().split(" ")[1]
 
+        from_month = cal_header.split("-")[0].strip()
+        to_month = cal_header.split("-")[1].strip().split(" ")[0]
+        to_year = from_year = cal_header.split("-")[1].strip().split(" ")[1]
         # if main month contains a year, set it (maybe happens in december???)
-        if len(main_month.split(" ")) > 1:
-            main_year = main_month.split(" ")[1]
-            main_month = main_month.split(" ")[0]
+        if len(from_month.split(" ")) > 1:
+            from_year = from_month.split(" ")[1]
+            from_month = from_month.split(" ")[0]
+
+        today_div = soup.find("table", id="cal").find("td", class_="today")
+        print(today_div)
+
+        # if other-month is to_month
+        if (
+            "other-month" in today_div.attrs
+            and datetime.now().strftime("%B") != to_month
+        ):
+            main_month, other_month = from_month, to_month
+            main_year, other_year = from_year, to_year
+        else:  # if other-month is from_month
+            main_month, other_month = to_month, from_month
+            main_year, other_year = to_year, from_year
 
         entries = []
 
@@ -172,15 +185,9 @@
         ):
             parent_td = pickup.parent
             month = (
-                main_month
-                if "main-month" in parent_td.attrs["class"]
-                else secondary_month
-            )
-            year = (
-                main_year
-                if "main-month" in parent_td.attrs["class"]
-                else secondary_year
+                main_month if "main-month" in parent_td.attrs["class"] else other_month
             )
+            year = main_year if "main-month" in parent_td.attrs["class"] else other_year
             day = parent_td.find("div", {"class": "daynumber"}).text
 
             # Iterate over all pickup container types for this day
@@ -188,9 +195,7 @@
                 container_type = " ".join(container.find("div").attrs["class"])
                 container_icon = ICON_MAP.get(container_type)
 
-                date = datetime.datetime.strptime(
-                    f"{year}-{month}-{day}", "%Y-%B-%d"
-                ).date()
+                date = datetime.strptime(f"{year}-{month}-{day}", "%Y-%B-%d").date()
                 entries.append(
                     Collection(date=date, t=container_type, icon=container_icon)
                 )

{"golden_diff": "diff --git a/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py b/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py\n--- a/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py\n+++ b/custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py\n@@ -1,6 +1,6 @@\n-import datetime\n import logging\n import re\n+from datetime import datetime\n \n import requests\n import urllib3\n@@ -153,15 +153,28 @@\n \n         soup = BeautifulSoup(r.text, \"html.parser\")\n         cal_header = soup.find(\"th\", {\"class\": \"header-month\"}).find(\"span\").text\n-        main_month = cal_header.split(\"-\")[0].strip()\n-\n-        secondary_month = cal_header.split(\"-\")[1].strip().split(\" \")[0]\n-        secondary_year = main_year = cal_header.split(\"-\")[1].strip().split(\" \")[1]\n \n+        from_month = cal_header.split(\"-\")[0].strip()\n+        to_month = cal_header.split(\"-\")[1].strip().split(\" \")[0]\n+        to_year = from_year = cal_header.split(\"-\")[1].strip().split(\" \")[1]\n         # if main month contains a year, set it (maybe happens in december???)\n-        if len(main_month.split(\" \")) > 1:\n-            main_year = main_month.split(\" \")[1]\n-            main_month = main_month.split(\" \")[0]\n+        if len(from_month.split(\" \")) > 1:\n+            from_year = from_month.split(\" \")[1]\n+            from_month = from_month.split(\" \")[0]\n+\n+        today_div = soup.find(\"table\", id=\"cal\").find(\"td\", class_=\"today\")\n+        print(today_div)\n+\n+        # if other-month is to_month\n+        if (\n+            \"other-month\" in today_div.attrs\n+            and datetime.now().strftime(\"%B\") != to_month\n+        ):\n+            main_month, other_month = from_month, to_month\n+            main_year, other_year = from_year, to_year\n+        else:  # if other-month is from_month\n+            main_month, other_month = to_month, from_month\n+            main_year, other_year = to_year, from_year\n \n         entries = []\n \n@@ -172,15 +185,9 @@\n         ):\n             parent_td = pickup.parent\n             month = (\n-                main_month\n-                if \"main-month\" in parent_td.attrs[\"class\"]\n-                else secondary_month\n-            )\n-            year = (\n-                main_year\n-                if \"main-month\" in parent_td.attrs[\"class\"]\n-                else secondary_year\n+                main_month if \"main-month\" in parent_td.attrs[\"class\"] else other_month\n             )\n+            year = main_year if \"main-month\" in parent_td.attrs[\"class\"] else other_year\n             day = parent_td.find(\"div\", {\"class\": \"daynumber\"}).text\n \n             # Iterate over all pickup container types for this day\n@@ -188,9 +195,7 @@\n                 container_type = \" \".join(container.find(\"div\").attrs[\"class\"])\n                 container_icon = ICON_MAP.get(container_type)\n \n-                date = datetime.datetime.strptime(\n-                    f\"{year}-{month}-{day}\", \"%Y-%B-%d\"\n-                ).date()\n+                date = datetime.strptime(f\"{year}-{month}-{day}\", \"%Y-%B-%d\").date()\n                 entries.append(\n                     Collection(date=date, t=container_type, icon=container_icon)\n                 )\n", "issue": "[Bug]: portenf_sa_gov_au reporting incorrect dates\n### I Have A Problem With:\r\n\r\nA specific source\r\n\r\n### What's Your Problem\r\n\r\nThe portenf_sa_gov_au sensor has been reporting incorrectly since it updated itself on 24 December 2023 (I can see this from HA logs). It appears that when there is 1 week or less left in the month \"main-month\" switches to the coming month and \"other-month\" becomes the current month.\r\n\r\nBecause of this, the integration reports the current collection next month and the next collections as in the past (and hides them).\r\n\r\nThe fix in #1110 by @5ila5 partly addresses the problem but it was not foreseeable to him that EOM would be treated this way. @5ila5 also noted that this might be an issue in that closed issue.\r\n\r\n### Source (if relevant)\r\n\r\nportenf_sa_gov_au\r\n\r\n### Logs\r\n\r\n```Shell\r\nOutput of test_sources.py:\r\n\r\nTesting source portenf_sa_gov_au ...\r\n  found 8 entries for Broadview, Regency Road, 565\r\n    2024-01-26 : general-waste bin [mdi:trash-can]\r\n    2024-01-26 : recycling bin [mdi:recycle]\r\n    2023-12-02 : general-waste bin [mdi:trash-can]\r\n    2023-12-02 : organics bin [mdi:leaf]\r\n    2023-12-09 : general-waste bin [mdi:trash-can]\r\n    2023-12-09 : recycling bin [mdi:recycle]\r\n    2023-12-16 : general-waste bin [mdi:trash-can]\r\n    2023-12-16 : organics bin [mdi:leaf]\r\n  found 8 entries for 48 Floriedale Rd\r\n    2024-01-26 : general-waste bin [mdi:trash-can]\r\n    2024-01-26 : recycling bin [mdi:recycle]\r\n    2023-12-02 : general-waste bin [mdi:trash-can]\r\n    2023-12-02 : organics bin [mdi:leaf]\r\n    2023-12-09 : general-waste bin [mdi:trash-can]\r\n    2023-12-09 : recycling bin [mdi:recycle]\r\n    2023-12-16 : general-waste bin [mdi:trash-can]\r\n    2023-12-16 : organics bin [mdi:leaf]\r\n  found 8 entries for 24 Margaret Terrace\r\n    2024-01-28 : general-waste bin [mdi:trash-can]\r\n    2024-01-28 : organics bin [mdi:leaf]\r\n    2023-12-04 : general-waste bin [mdi:trash-can]\r\n    2023-12-04 : recycling bin [mdi:recycle]\r\n    2023-12-11 : general-waste bin [mdi:trash-can]\r\n    2023-12-11 : organics bin [mdi:leaf]\r\n    2023-12-18 : general-waste bin [mdi:trash-can]\r\n    2023-12-18 : recycling bin [mdi:recycle]\r\n  found 8 entries for Addison Road 91 with unit\r\n    2024-01-28 : general-waste bin [mdi:trash-can]\r\n    2024-01-28 : organics bin [mdi:leaf]\r\n    2023-12-04 : general-waste bin [mdi:trash-can]\r\n    2023-12-04 : recycling bin [mdi:recycle]\r\n    2023-12-11 : general-waste bin [mdi:trash-can]\r\n    2023-12-11 : organics bin [mdi:leaf]\r\n    2023-12-18 : general-waste bin [mdi:trash-can]\r\n    2023-12-18 : recycling bin [mdi:recycle]\r\n```\r\n\r\n\r\n### Relevant Configuration\r\n\r\n_No response_\r\n\r\n### Checklist Source Error\r\n\r\n- [X] Use the example parameters for your source (often available in the documentation) (don't forget to restart Home Assistant after changing the configuration)\r\n- [X] Checked that the website of your service provider is still working\r\n- [X] Tested my attributes on the service provider website (if possible)\r\n- [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)\r\n\r\n### Checklist Sensor Error\r\n\r\n- [X] Checked in the Home Assistant Calendar tab if the event names match the types names (if types argument is used)\r\n\r\n### Required\r\n\r\n- [X] I have searched past (closed AND opened) issues to see if this bug has already been reported, and it hasn't been.\r\n- [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.\n", "before_files": [{"content": "import datetime\nimport logging\nimport re\n\nimport requests\nimport urllib3\nfrom bs4 import BeautifulSoup\nfrom waste_collection_schedule import Collection  # type: ignore[attr-defined]\n\n# With verify=True the POST fails due to a SSLCertVerificationError.\n# Using verify=False works, but is not ideal. The following links may provide a better way of dealing with this:\n# https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings\n# https://urllib3.readthedocs.io/en/1.26.x/user-guide.html#ssl\n# These two lines areused to suppress the InsecureRequestWarning when using verify=False\nurllib3.disable_warnings()\n\nTITLE = \"Port Adelaide Enfield, South Australia\"\nDESCRIPTION = \"Source for City of Port Adelaide Enfield, South Australia.\"\nURL = \"https://ecouncil.portenf.sa.gov.au/\"\nTEST_CASES = {\n    \"Broadview, Regency Road, 565 \": {\n        \"suburb\": \"Broadview\",\n        \"street\": \"Regency Road\",\n        \"house_number\": 565,\n        \"unit_number\": \"\",\n    },\n    \"48 Floriedale Rd \": {\n        \"suburb\": \"Greenacres\",\n        \"street\": \"Floriedale Rd\",\n        \"house_number\": \"48\",\n    },\n    \"24 Margaret Terrace\": {\n        \"suburb\": \"Rosewater\",\n        \"street\": \"Margaret Terrace\",\n        \"house_number\": \"24\",\n    },\n    \"Addison Road 91 with unit\": {\n        \"suburb\": \"Rosewater\",\n        \"street\": \"Addison Road\",\n        \"house_number\": 91,\n        \"unit_number\": 2,\n    },\n}\n\nICON_MAP = {\n    \"general-waste bin\": \"mdi:trash-can\",\n    \"organics bin\": \"mdi:leaf\",\n    \"recycling bin\": \"mdi:recycle\",\n}\n\nLOGGER = logging.getLogger(__name__)\n\nAPI_URL = \"https://ecouncil.portenf.sa.gov.au/public/propertywastedates/public.aspx\"\n\n\nclass Source:\n    def __init__(\n        self,\n        suburb: str,\n        street: str,\n        house_number: str | int,\n        unit_number: str | int = \"\",\n    ):\n        self._suburb: str = suburb\n        self._street: str = street\n        self._house_number: str = str(house_number)\n        self._unit_number: str = str(unit_number)\n\n    def __set_args(\n        self, soup: BeautifulSoup, event_taget=None, additional: dict = {}\n    ) -> dict:\n        args = {\n            \"ctl00$MainContent$txtSuburb\": self._suburb,\n            \"ctl00$MainContent$txtStreetName\": self._street,\n            \"ctl00$MainContent$txtHouseNumber\": self._house_number,\n            \"ctl00$MainContent$txtUnitNumber\": self._unit_number,\n        }\n        if event_taget is not None:\n            args[\"__EVENTTARGET\"] = event_taget\n\n        for hidden_val in soup.find_all(\"input\", {\"type\": \"hidden\"}):\n            args[hidden_val[\"name\"]] = hidden_val[\"value\"]\n\n        for key, value in additional.items():\n            args[key] = value\n        return args\n\n    def fetch(self):\n        session = requests.Session()\n\n        # get First page\n        r = session.get(API_URL, verify=False)\n        r.raise_for_status()\n\n        # extractt arguments\n        args = self.__set_args(\n            BeautifulSoup(r.text, \"html.parser\"),\n            event_taget=\"ctl00$MainContent$btnSearch\",\n        )\n\n        r = session.post(API_URL, data=args)\n        r.raise_for_status()\n\n        # get page to select an address\n        soup = BeautifulSoup(r.text, \"html.parser\")\n\n        selectable = soup.find_all(\"a\", {\"class\": \"anchor-button small\"}, text=\"Select\")\n\n        if len(selectable) == 0:\n            raise ValueError(\"No address found\")\n        selected = selectable[0]\n\n        # If multiple addresses are found, try to find the one that matches the input and warn if there are multiple or none matches\n        if len(selectable) > 1:\n            found = [\n                \" \".join(\n                    [y.text for y in x.parent.parent.find_all(\"td\")[1].find_all(\"span\")]\n                )\n                for x in selectable\n            ]\n            using_index = 0\n\n            match = False\n\n            for index, entry in enumerate(found):\n                entry = entry.lower().strip().replace(\"  \", \"\")\n                if (\n                    self._house_number.lower().strip().replace(\"  \", \"\") in entry\n                    and self._street.lower().strip().replace(\"  \", \"\") in entry\n                    and self._suburb.lower().strip().replace(\"  \", \"\") in entry\n                    and self._unit_number.lower().strip().replace(\"  \", \"\") in entry\n                ):\n                    if match:\n                        LOGGER.warning(\n                            f\"Multiple addresses found, using first one \\nfound:{', '.join(found[:10])}{'...' if len(found) >= 10 else ''} \\nusing:{found[using_index]}\"\n                        )\n                        break\n                    using_index = index\n                    match = True\n            if not match:\n                LOGGER.warning(\n                    f\"no perfect address match found, using:{found[using_index]}\"\n                )\n\n        # request first address\n        args = self.__set_args(\n            soup,\n            event_taget=\"ctl00$MainContent$gvPropertyResults$ctl02$btnSelect\",\n            additional={selected[\"href\"].split(\"'\")[1]: \"\"},\n        )\n        r = session.post(API_URL, data=args)\n        r.raise_for_status()\n\n        soup = BeautifulSoup(r.text, \"html.parser\")\n        cal_header = soup.find(\"th\", {\"class\": \"header-month\"}).find(\"span\").text\n        main_month = cal_header.split(\"-\")[0].strip()\n\n        secondary_month = cal_header.split(\"-\")[1].strip().split(\" \")[0]\n        secondary_year = main_year = cal_header.split(\"-\")[1].strip().split(\" \")[1]\n\n        # if main month contains a year, set it (maybe happens in december???)\n        if len(main_month.split(\" \")) > 1:\n            main_year = main_month.split(\" \")[1]\n            main_month = main_month.split(\" \")[0]\n\n        entries = []\n\n        calendar = soup.find(\"table\", {\"class\": \"collection-day-calendar\"})\n        # Iterate over all days with pickups\n        for pickup in calendar.find_all(\n            \"div\", {\"class\": re.compile(r\"pickup|next-pickup\")}\n        ):\n            parent_td = pickup.parent\n            month = (\n                main_month\n                if \"main-month\" in parent_td.attrs[\"class\"]\n                else secondary_month\n            )\n            year = (\n                main_year\n                if \"main-month\" in parent_td.attrs[\"class\"]\n                else secondary_year\n            )\n            day = parent_td.find(\"div\", {\"class\": \"daynumber\"}).text\n\n            # Iterate over all pickup container types for this day\n            for container in pickup.find_all(\"div\", {\"class\": \"bin-container\"}):\n                container_type = \" \".join(container.find(\"div\").attrs[\"class\"])\n                container_icon = ICON_MAP.get(container_type)\n\n                date = datetime.datetime.strptime(\n                    f\"{year}-{month}-{day}\", \"%Y-%B-%d\"\n                ).date()\n                entries.append(\n                    Collection(date=date, t=container_type, icon=container_icon)\n                )\n\n        return entries\n", "path": "custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py"}], "after_files": [{"content": "import logging\nimport re\nfrom datetime import datetime\n\nimport requests\nimport urllib3\nfrom bs4 import BeautifulSoup\nfrom waste_collection_schedule import Collection  # type: ignore[attr-defined]\n\n# With verify=True the POST fails due to a SSLCertVerificationError.\n# Using verify=False works, but is not ideal. The following links may provide a better way of dealing with this:\n# https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings\n# https://urllib3.readthedocs.io/en/1.26.x/user-guide.html#ssl\n# These two lines areused to suppress the InsecureRequestWarning when using verify=False\nurllib3.disable_warnings()\n\nTITLE = \"Port Adelaide Enfield, South Australia\"\nDESCRIPTION = \"Source for City of Port Adelaide Enfield, South Australia.\"\nURL = \"https://ecouncil.portenf.sa.gov.au/\"\nTEST_CASES = {\n    \"Broadview, Regency Road, 565 \": {\n        \"suburb\": \"Broadview\",\n        \"street\": \"Regency Road\",\n        \"house_number\": 565,\n        \"unit_number\": \"\",\n    },\n    \"48 Floriedale Rd \": {\n        \"suburb\": \"Greenacres\",\n        \"street\": \"Floriedale Rd\",\n        \"house_number\": \"48\",\n    },\n    \"24 Margaret Terrace\": {\n        \"suburb\": \"Rosewater\",\n        \"street\": \"Margaret Terrace\",\n        \"house_number\": \"24\",\n    },\n    \"Addison Road 91 with unit\": {\n        \"suburb\": \"Rosewater\",\n        \"street\": \"Addison Road\",\n        \"house_number\": 91,\n        \"unit_number\": 2,\n    },\n}\n\nICON_MAP = {\n    \"general-waste bin\": \"mdi:trash-can\",\n    \"organics bin\": \"mdi:leaf\",\n    \"recycling bin\": \"mdi:recycle\",\n}\n\nLOGGER = logging.getLogger(__name__)\n\nAPI_URL = \"https://ecouncil.portenf.sa.gov.au/public/propertywastedates/public.aspx\"\n\n\nclass Source:\n    def __init__(\n        self,\n        suburb: str,\n        street: str,\n        house_number: str | int,\n        unit_number: str | int = \"\",\n    ):\n        self._suburb: str = suburb\n        self._street: str = street\n        self._house_number: str = str(house_number)\n        self._unit_number: str = str(unit_number)\n\n    def __set_args(\n        self, soup: BeautifulSoup, event_taget=None, additional: dict = {}\n    ) -> dict:\n        args = {\n            \"ctl00$MainContent$txtSuburb\": self._suburb,\n            \"ctl00$MainContent$txtStreetName\": self._street,\n            \"ctl00$MainContent$txtHouseNumber\": self._house_number,\n            \"ctl00$MainContent$txtUnitNumber\": self._unit_number,\n        }\n        if event_taget is not None:\n            args[\"__EVENTTARGET\"] = event_taget\n\n        for hidden_val in soup.find_all(\"input\", {\"type\": \"hidden\"}):\n            args[hidden_val[\"name\"]] = hidden_val[\"value\"]\n\n        for key, value in additional.items():\n            args[key] = value\n        return args\n\n    def fetch(self):\n        session = requests.Session()\n\n        # get First page\n        r = session.get(API_URL, verify=False)\n        r.raise_for_status()\n\n        # extractt arguments\n        args = self.__set_args(\n            BeautifulSoup(r.text, \"html.parser\"),\n            event_taget=\"ctl00$MainContent$btnSearch\",\n        )\n\n        r = session.post(API_URL, data=args)\n        r.raise_for_status()\n\n        # get page to select an address\n        soup = BeautifulSoup(r.text, \"html.parser\")\n\n        selectable = soup.find_all(\"a\", {\"class\": \"anchor-button small\"}, text=\"Select\")\n\n        if len(selectable) == 0:\n            raise ValueError(\"No address found\")\n        selected = selectable[0]\n\n        # If multiple addresses are found, try to find the one that matches the input and warn if there are multiple or none matches\n        if len(selectable) > 1:\n            found = [\n                \" \".join(\n                    [y.text for y in x.parent.parent.find_all(\"td\")[1].find_all(\"span\")]\n                )\n                for x in selectable\n            ]\n            using_index = 0\n\n            match = False\n\n            for index, entry in enumerate(found):\n                entry = entry.lower().strip().replace(\"  \", \"\")\n                if (\n                    self._house_number.lower().strip().replace(\"  \", \"\") in entry\n                    and self._street.lower().strip().replace(\"  \", \"\") in entry\n                    and self._suburb.lower().strip().replace(\"  \", \"\") in entry\n                    and self._unit_number.lower().strip().replace(\"  \", \"\") in entry\n                ):\n                    if match:\n                        LOGGER.warning(\n                            f\"Multiple addresses found, using first one \\nfound:{', '.join(found[:10])}{'...' if len(found) >= 10 else ''} \\nusing:{found[using_index]}\"\n                        )\n                        break\n                    using_index = index\n                    match = True\n            if not match:\n                LOGGER.warning(\n                    f\"no perfect address match found, using:{found[using_index]}\"\n                )\n\n        # request first address\n        args = self.__set_args(\n            soup,\n            event_taget=\"ctl00$MainContent$gvPropertyResults$ctl02$btnSelect\",\n            additional={selected[\"href\"].split(\"'\")[1]: \"\"},\n        )\n        r = session.post(API_URL, data=args)\n        r.raise_for_status()\n\n        soup = BeautifulSoup(r.text, \"html.parser\")\n        cal_header = soup.find(\"th\", {\"class\": \"header-month\"}).find(\"span\").text\n\n        from_month = cal_header.split(\"-\")[0].strip()\n        to_month = cal_header.split(\"-\")[1].strip().split(\" \")[0]\n        to_year = from_year = cal_header.split(\"-\")[1].strip().split(\" \")[1]\n        # if main month contains a year, set it (maybe happens in december???)\n        if len(from_month.split(\" \")) > 1:\n            from_year = from_month.split(\" \")[1]\n            from_month = from_month.split(\" \")[0]\n\n        today_div = soup.find(\"table\", id=\"cal\").find(\"td\", class_=\"today\")\n        print(today_div)\n\n        # if other-month is to_month\n        if (\n            \"other-month\" in today_div.attrs\n            and datetime.now().strftime(\"%B\") != to_month\n        ):\n            main_month, other_month = from_month, to_month\n            main_year, other_year = from_year, to_year\n        else:  # if other-month is from_month\n            main_month, other_month = to_month, from_month\n            main_year, other_year = to_year, from_year\n\n        entries = []\n\n        calendar = soup.find(\"table\", {\"class\": \"collection-day-calendar\"})\n        # Iterate over all days with pickups\n        for pickup in calendar.find_all(\n            \"div\", {\"class\": re.compile(r\"pickup|next-pickup\")}\n        ):\n            parent_td = pickup.parent\n            month = (\n                main_month if \"main-month\" in parent_td.attrs[\"class\"] else other_month\n            )\n            year = main_year if \"main-month\" in parent_td.attrs[\"class\"] else other_year\n            day = parent_td.find(\"div\", {\"class\": \"daynumber\"}).text\n\n            # Iterate over all pickup container types for this day\n            for container in pickup.find_all(\"div\", {\"class\": \"bin-container\"}):\n                container_type = \" \".join(container.find(\"div\").attrs[\"class\"])\n                container_icon = ICON_MAP.get(container_type)\n\n                date = datetime.strptime(f\"{year}-{month}-{day}\", \"%Y-%B-%d\").date()\n                entries.append(\n                    Collection(date=date, t=container_type, icon=container_icon)\n                )\n\n        return entries\n", "path": "custom_components/waste_collection_schedule/waste_collection_schedule/source/portenf_sa_gov_au.py"}]}