uk_bin_collection 0.150.1__py3-none-any.whl → 0.151.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1935,6 +1935,7 @@
1935
1935
  "skip_get_url": true,
1936
1936
  "uprn": "100070182634",
1937
1937
  "url": "https://www.rugby.gov.uk/check-your-next-bin-day",
1938
+ "web_driver": "http://selenium:4444",
1938
1939
  "wiki_name": "Rugby",
1939
1940
  "wiki_note": "Provide your UPRN and postcode. You can find your UPRN using [FindMyAddress](https://www.findmyaddress.co.uk/search).",
1940
1941
  "LAD24CD": "E07000220"
@@ -8,8 +8,6 @@ from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataC
8
8
 
9
9
 
10
10
  # import the wonderful Beautiful Soup and the URL grabber
11
-
12
-
13
11
  class CouncilClass(AbstractGetBinDataClass):
14
12
  """
15
13
  Concrete classes have to implement all abstract operations of the
@@ -74,42 +74,56 @@ class CouncilClass(AbstractGetBinDataClass):
74
74
  )
75
75
 
76
76
  if service_details:
77
-
78
- # Extract next collection date
77
+ # Extract next collection date only
79
78
  next_collection_row = service_details.find(
80
79
  "dt", string="Next collection"
81
80
  )
82
- next_collection = (
83
- next_collection_row.find_next_sibling("dd").get_text(
84
- strip=True
85
- )
86
- if next_collection_row
87
- else "Unknown"
88
- )
89
-
90
- # Parse dates into standard dd/mm/yyyy format
91
- next_collection_date = datetime.strptime(
92
- remove_ordinal_indicator_from_date_string(next_collection),
93
- "%A, %d %B",
94
- )
95
-
96
- if (datetime.now().month == 12) and (
97
- next_collection.month == 1
98
- ):
99
- next_collection_date = next_collection_date.replace(
100
- year=next_year
81
+ if next_collection_row:
82
+ next_collection = next_collection_row.find_next_sibling(
83
+ "dd"
84
+ ).get_text(strip=True)
85
+
86
+ # Remove the adjusted collection time message
87
+ if (
88
+ "(this collection has been adjusted from its usual time)"
89
+ in next_collection
90
+ ):
91
+ next_collection = next_collection.replace(
92
+ "(this collection has been adjusted from its usual time)",
93
+ "",
94
+ ).strip()
95
+
96
+ # Parse date from format like "Wednesday, 7th May"
97
+ next_collection = remove_ordinal_indicator_from_date_string(
98
+ next_collection
101
99
  )
102
- else:
103
- next_collection_date = next_collection_date.replace(
104
- year=current_year
105
- )
106
-
107
- dict_data = {
108
- "type": collection_type.strip(),
109
- "collectionDate": next_collection_date.strftime(
110
- date_format
111
- ),
112
- }
113
- data["bins"].append(dict_data)
100
+ try:
101
+ next_collection_date = datetime.strptime(
102
+ next_collection, "%A, %d %B"
103
+ )
104
+
105
+ # Handle year rollover
106
+ if (
107
+ datetime.now().month == 12
108
+ and next_collection_date.month == 1
109
+ ):
110
+ next_collection_date = next_collection_date.replace(
111
+ year=next_year
112
+ )
113
+ else:
114
+ next_collection_date = next_collection_date.replace(
115
+ year=current_year
116
+ )
117
+
118
+ dict_data = {
119
+ "type": collection_type.strip(),
120
+ "collectionDate": next_collection_date.strftime(
121
+ date_format
122
+ ),
123
+ }
124
+ data["bins"].append(dict_data)
125
+ print(dict_data)
126
+ except ValueError as e:
127
+ print(f"Error parsing date {next_collection}: {e}")
114
128
 
115
129
  return data
@@ -0,0 +1,115 @@
1
+ import time
2
+ from datetime import datetime
3
+
4
+ from bs4 import BeautifulSoup
5
+ from selenium.webdriver.common.by import By
6
+ from selenium.webdriver.support import expected_conditions as EC
7
+ from selenium.webdriver.support.ui import Select
8
+ from selenium.webdriver.support.wait import WebDriverWait
9
+
10
+ from uk_bin_collection.uk_bin_collection.common import *
11
+ from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
12
+
13
+ # import the wonderful Beautiful Soup and the URL grabber
14
+
15
+
16
+ class CouncilClass(AbstractGetBinDataClass):
17
+ """
18
+ Concrete classes have to implement all abstract operations of the
19
+ base class. They can also override some operations with a default
20
+ implementation.
21
+ """
22
+
23
+ def parse_data(self, page: str, **kwargs) -> dict:
24
+ driver = None
25
+ try:
26
+ page = "https://my.maidstone.gov.uk/service/Find-your-bin-day"
27
+ bin_data = {"bins": []}
28
+ user_paon = kwargs.get("paon")
29
+ user_postcode = kwargs.get("postcode")
30
+ web_driver = kwargs.get("web_driver")
31
+ headless = kwargs.get("headless")
32
+ check_postcode(user_postcode)
33
+
34
+ # Create Selenium webdriver
35
+ driver = create_webdriver(web_driver, headless, None, __name__)
36
+ driver.get(page)
37
+
38
+ iframe_presense = WebDriverWait(driver, 30).until(
39
+ EC.presence_of_element_located((By.ID, "fillform-frame-1"))
40
+ )
41
+ driver.switch_to.frame(iframe_presense)
42
+
43
+ wait = WebDriverWait(driver, 60)
44
+
45
+ # Postal code input
46
+ inputElement_postcodesearch = wait.until(
47
+ EC.element_to_be_clickable((By.NAME, "postcode"))
48
+ )
49
+ inputElement_postcodesearch.send_keys(user_postcode)
50
+
51
+ # Wait for the 'Select address' dropdown to be updated
52
+ dropdown_select = wait.until(
53
+ EC.presence_of_element_located((By.XPATH, "//span[contains(text(), 'Select...')]"))
54
+ )
55
+ dropdown_select.click()
56
+
57
+ dropdown = wait.until(
58
+ EC.element_to_be_clickable((By.XPATH, f"//div[contains(text(), ' {user_paon}')]"))
59
+ )
60
+ dropdown.click()
61
+
62
+ # Wait for 'Searching for...' to be added to page
63
+ WebDriverWait(driver, timeout=15).until(
64
+ EC.text_to_be_present_in_element(
65
+ (By.CSS_SELECTOR, "span[data-name=html1]"), "Searching"
66
+ )
67
+ )
68
+
69
+ # Wait for 'Searching for...' to be removed from page
70
+ WebDriverWait(driver, timeout=15).until(
71
+ EC.none_of(
72
+ EC.text_to_be_present_in_element(
73
+ (By.CSS_SELECTOR, "span[data-name=html1]"), "Searching"
74
+ )
75
+ )
76
+ )
77
+
78
+ # Even then it can still be adding data to the page...
79
+ time.sleep(5)
80
+
81
+ soup = BeautifulSoup(driver.page_source, features="html.parser")
82
+
83
+ # This is ugly but there is literally no consistency to the HTML
84
+ def is_a_collection_date(t):
85
+ return any("Next collection" in c for c in t.children)
86
+
87
+ for next_collection in soup.find_all(is_a_collection_date):
88
+ bin_info = list(
89
+ next_collection.parent.select_one("div:nth-child(1)").children
90
+ )
91
+ if not bin_info:
92
+ continue
93
+ bin = bin_info[0].get_text()
94
+ date = next_collection.select_one("strong").get_text(strip=True)
95
+ bin_date = datetime.strptime(date, "%d %b %Y")
96
+ dict_data = {
97
+ "type": bin,
98
+ "collectionDate": bin_date.strftime(date_format),
99
+ }
100
+ bin_data["bins"].append(dict_data)
101
+
102
+ bin_data["bins"].sort(
103
+ key=lambda x: datetime.strptime(x.get("collectionDate"), date_format)
104
+ )
105
+
106
+ except Exception as e:
107
+ # Here you can log the exception if needed
108
+ print(f"An error occurred: {e}")
109
+ # Optionally, re-raise the exception if you want it to propagate
110
+ raise
111
+ finally:
112
+ # This block ensures that the driver is closed regardless of an exception
113
+ if driver:
114
+ driver.quit()
115
+ return bin_data
@@ -1,4 +1,11 @@
1
+ import time
2
+
1
3
  from bs4 import BeautifulSoup
4
+ from selenium.webdriver.common.by import By
5
+ from selenium.webdriver.common.keys import Keys
6
+ from selenium.webdriver.support import expected_conditions as EC
7
+ from selenium.webdriver.support.ui import Select, WebDriverWait
8
+
2
9
  from uk_bin_collection.uk_bin_collection.common import *
3
10
  from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
4
11
 
@@ -12,78 +19,128 @@ class CouncilClass(AbstractGetBinDataClass):
12
19
  """
13
20
 
14
21
  def parse_data(self, page: str, **kwargs) -> dict:
15
- data = {"bins": []}
16
- collections = []
17
-
18
- user_postcode = kwargs.get("postcode")
19
- user_uprn = kwargs.get("uprn")
20
-
21
- check_uprn(user_uprn)
22
- check_postcode(user_postcode)
23
-
24
- headers = {
25
- "authority": "www.rugby.gov.uk",
26
- "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
27
- "accept-language": "en-GB,en;q=0.9",
28
- "cache-control": "no-cache",
29
- "content-type": "application/x-www-form-urlencoded",
30
- # 'cookie': 'JSESSIONID=7E90CAB54B649C3DCC7F6B5DA0897C63; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=en_GB; AWSELB=D941E98916B5759862ED6C39DA9FB3FD9880491851D200C98112ABEC3223D52B19A2A2C6B37A89D3650D44FA5728FCAFEDE7BB2592D948FFF9C7B18D76C41AF02C308B0F3A2DE17F1585E9959BCE68CC83BC3AC753; CookieControl={"necessaryCookies":[],"optionalCookies":{},"statement":{},"consentDate":1701710876715,"consentExpiry":90,"interactedWith":true,"user":"8FED8810-3C3E-4D50-A9DC-42655030B3B1"}',
31
- "origin": "https://www.rugby.gov.uk",
32
- "pragma": "no-cache",
33
- "referer": "https://www.rugby.gov.uk/check-your-next-bin-day",
34
- "sec-ch-ua": '"Chromium";v="118", "Opera GX";v="104", "Not=A?Brand";v="99"',
35
- "sec-ch-ua-mobile": "?0",
36
- "sec-ch-ua-platform": '"Windows"',
37
- "sec-fetch-dest": "document",
38
- "sec-fetch-mode": "navigate",
39
- "sec-fetch-site": "same-origin",
40
- "sec-fetch-user": "?1",
41
- "upgrade-insecure-requests": "1",
42
- "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.5993.118 Safari/537.36",
43
- }
44
- params = {
45
- "p_p_id": "com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet",
46
- "p_p_lifecycle": "0",
47
- "p_p_state": "normal",
48
- "p_p_mode": "view",
49
- "_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet_mvcRenderCommandName": "/collection_day_finder/get_days",
50
- }
51
- data = {
52
- "_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet_formDate": f"{datetime.now().timestamp().__floor__()}",
53
- "_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet_postcode": f"{user_postcode}",
54
- "_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet_uprn": f"{user_uprn}",
55
- }
56
-
57
- response = requests.post(
58
- "https://www.rugby.gov.uk/check-your-next-bin-day",
59
- params=params,
60
- headers=headers,
61
- data=data,
62
- )
63
-
64
- soup = BeautifulSoup(response.text, features="html.parser")
65
- soup.prettify()
66
-
67
- table_rows = soup.find("table", {"class": "table"}).find("tbody").find_all("tr")
68
-
69
- for row in table_rows:
70
- row_text = row.text.strip().split("\n")
71
- bin_text = row_text[0].split(" ")
72
- bin_type = " ".join(bin_text[1:]).capitalize()
73
- collections.append(
74
- (bin_type, datetime.strptime(row_text[1], "%A %d %b %Y"))
22
+ driver = None
23
+ try:
24
+ user_postcode = kwargs.get("postcode")
25
+ if not user_postcode:
26
+ raise ValueError("No postcode provided.")
27
+ check_postcode(user_postcode)
28
+
29
+ user_uprn = kwargs.get("uprn")
30
+ check_uprn(user_uprn)
31
+
32
+ headless = kwargs.get("headless")
33
+ web_driver = kwargs.get("web_driver")
34
+ driver = create_webdriver(web_driver, headless, None, __name__)
35
+ page = "https://www.rugby.gov.uk/check-your-next-bin-day"
36
+
37
+ driver.get(page)
38
+
39
+ wait = WebDriverWait(driver, 60)
40
+ accept_cookies_button = wait.until(
41
+ EC.element_to_be_clickable(
42
+ (
43
+ By.ID,
44
+ "ccc-recommended-settings",
45
+ )
46
+ )
75
47
  )
76
- collections.append(
77
- (bin_type, datetime.strptime(row_text[3], "%A %d %b %Y"))
48
+ accept_cookies_button.click()
49
+
50
+ postcode_input = WebDriverWait(driver, 10).until(
51
+ EC.presence_of_element_located(
52
+ (
53
+ By.XPATH,
54
+ '//*[@id="_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet_postcode"]',
55
+ )
56
+ )
57
+ )
58
+ postcode_input.send_keys(user_postcode + Keys.TAB + Keys.ENTER)
59
+
60
+ time.sleep(5)
61
+ # Wait for address box to be visible
62
+ select_address_input = WebDriverWait(driver, 10).until(
63
+ EC.presence_of_element_located(
64
+ (
65
+ By.ID,
66
+ "_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet_uprn",
67
+ )
68
+ )
69
+ )
70
+
71
+ # Select address based
72
+ select = Select(select_address_input)
73
+ for option in select.options:
74
+ if option.get_attribute("value") == str(user_uprn):
75
+ select.select_by_value(str(user_uprn))
76
+ break
77
+ else:
78
+ raise ValueError(f"UPRN {user_uprn} not found in address options")
79
+
80
+ select_address_input.send_keys(Keys.TAB + Keys.ENTER)
81
+
82
+ # Wait for the specified table to be present
83
+ target_table = WebDriverWait(driver, 10).until(
84
+ EC.presence_of_element_located(
85
+ (
86
+ By.XPATH,
87
+ '//*[@id="portlet_com_placecube_digitalplace_local_waste_portlet_CollectionDayFinderPortlet"]/div/div/div/div/table',
88
+ )
89
+ )
90
+ )
91
+
92
+ soup = BeautifulSoup(driver.page_source, "html.parser")
93
+
94
+ # Initialize bin data dictionary
95
+ bin_data = {"bins": []}
96
+
97
+ # Find the table
98
+ table = soup.find("table", class_="table")
99
+ if table:
100
+ # Find all rows in tbody
101
+ rows = table.find("tbody").find_all("tr")
102
+
103
+ for row in rows:
104
+ # Get all cells in the row
105
+ cells = row.find_all("td")
106
+ if len(cells) >= 4: # Ensure we have enough cells
107
+ bin_type = cells[0].text.strip()
108
+ next_collection = cells[1].text.strip()
109
+ following_collection = cells[3].text.strip()
110
+
111
+ # Parse the dates
112
+ for collection_date in [next_collection, following_collection]:
113
+ try:
114
+ # Convert date from "Friday 09 May 2025" format
115
+ parsed_date = datetime.strptime(
116
+ collection_date, "%A %d %B %Y"
117
+ )
118
+ formatted_date = parsed_date.strftime("%d/%m/%Y")
119
+
120
+ bin_info = {
121
+ "type": bin_type,
122
+ "collectionDate": formatted_date,
123
+ }
124
+ bin_data["bins"].append(bin_info)
125
+ except ValueError as e:
126
+ print(f"Error parsing date {collection_date}: {e}")
127
+ else:
128
+ raise ValueError("Collection data table not found")
129
+
130
+ # Sort the collections by date
131
+ bin_data["bins"].sort(
132
+ key=lambda x: datetime.strptime(x["collectionDate"], "%d/%m/%Y")
78
133
  )
79
134
 
80
- ordered_data = sorted(collections, key=lambda x: x[1])
81
- data = {"bins": []}
82
- for item in ordered_data:
83
- dict_data = {
84
- "type": item[0],
85
- "collectionDate": item[1].strftime(date_format),
86
- }
87
- data["bins"].append(dict_data)
135
+ print(bin_data)
88
136
 
89
- return data
137
+ except Exception as e:
138
+ # Here you can log the exception if needed
139
+ print(f"An error occurred: {e}")
140
+ # Optionally, re-raise the exception if you want it to propagate
141
+ raise
142
+ finally:
143
+ # This block ensures that the driver is closed regardless of an exception
144
+ if driver:
145
+ driver.quit()
146
+ return bin_data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uk_bin_collection
3
- Version: 0.150.1
3
+ Version: 0.151.0
4
4
  Summary: Python Lib to collect UK Bin Data
5
5
  Author: Robert Bradley
6
6
  Author-email: robbrad182@gmail.com
@@ -7,7 +7,7 @@ uk_bin_collection/tests/council_feature_input_parity.py,sha256=DO6Mk4ImYgM5ZCZ-c
7
7
  uk_bin_collection/tests/features/environment.py,sha256=VQZjJdJI_kZn08M0j5cUgvKT4k3iTw8icJge1DGOkoA,127
8
8
  uk_bin_collection/tests/features/validate_council_outputs.feature,sha256=SJK-Vc737hrf03tssxxbeg_JIvAH-ddB8f6gU1LTbuQ,251
9
9
  uk_bin_collection/tests/generate_map_test_results.py,sha256=CKnGK2ZgiSXomRGkomX90DitgMP-X7wkHhyKORDcL2E,1144
10
- uk_bin_collection/tests/input.json,sha256=dPgWnCRdDky-incNNaf9iYMI4i9wrkktRs4BZmIwyzE,131794
10
+ uk_bin_collection/tests/input.json,sha256=1E27u-92jfA9sMw0AzxCP-emvGQNq3GD8GWGbZjnPCQ,131840
11
11
  uk_bin_collection/tests/output.schema,sha256=ZwKQBwYyTDEM4G2hJwfLUVM-5v1vKRvRK9W9SS1sd18,1086
12
12
  uk_bin_collection/tests/step_defs/step_helpers/file_handler.py,sha256=Ygzi4V0S1MIHqbdstUlIqtRIwnynvhu4UtpweJ6-5N8,1474
13
13
  uk_bin_collection/tests/step_defs/test_validate_council.py,sha256=VZ0a81sioJULD7syAYHjvK_-nT_Rd36tUyzPetSA0gk,3475
@@ -23,7 +23,7 @@ uk_bin_collection/uk_bin_collection/councils/AdurAndWorthingCouncils.py,sha256=p
23
23
  uk_bin_collection/uk_bin_collection/councils/AmberValleyBoroughCouncil.py,sha256=mTeluIIEcuxLxhfDQ95A1fp8RM6AkJT5tRGZPUbYGdk,1853
24
24
  uk_bin_collection/uk_bin_collection/councils/AntrimAndNewtonabbeyCouncil.py,sha256=Hp5pteaC5RjL5ZqPZ564S9WQ6ZTKLMO6Dl_fxip2TUc,1653
25
25
  uk_bin_collection/uk_bin_collection/councils/ArdsAndNorthDownCouncil.py,sha256=iMBldxNErgi-ok1o6xpqdNgMvR6qapaNqoTWDTqMeGo,3824
26
- uk_bin_collection/uk_bin_collection/councils/ArgyllandButeCouncil.py,sha256=UnHge6FwigJKYuE6QYiXE659dTaKvs1xhHHJXoAXhSQ,5075
26
+ uk_bin_collection/uk_bin_collection/councils/ArgyllandButeCouncil.py,sha256=NBeXjzv0bOblkS5xjSy5D0DdW9vtx_TGMLVP0FP1JqA,5073
27
27
  uk_bin_collection/uk_bin_collection/councils/ArmaghBanbridgeCraigavonCouncil.py,sha256=o9NBbVCTdxKXnpYbP8-zxe1Gh8s57vwfV75Son_sAHE,2863
28
28
  uk_bin_collection/uk_bin_collection/councils/ArunCouncil.py,sha256=yfhthv9nuogP19VOZ3TYQrq51qqjiCZcSel4sXhiKjs,4012
29
29
  uk_bin_collection/uk_bin_collection/councils/AshfieldDistrictCouncil.py,sha256=fhX7S_A3jqoND7NE6qITPMPvdk3FJSKZ3Eoa5RtSg3I,4247
@@ -52,7 +52,7 @@ uk_bin_collection/uk_bin_collection/councils/BracknellForestCouncil.py,sha256=Ll
52
52
  uk_bin_collection/uk_bin_collection/councils/BradfordMDC.py,sha256=BEWS2c62cOsf26jqn1AkNUvVmc5AlUADYLaQuPn9RY4,5456
53
53
  uk_bin_collection/uk_bin_collection/councils/BraintreeDistrictCouncil.py,sha256=2vYHilpI8mSwC2Ykdr1gxYAN3excDWqF6AwtGbkwbTw,2441
54
54
  uk_bin_collection/uk_bin_collection/councils/BrecklandCouncil.py,sha256=PX6A_pDvaN109aSNWmEhm88GFKfkClIkmbwGURWvsks,1744
55
- uk_bin_collection/uk_bin_collection/councils/BrentCouncil.py,sha256=ucwokxvASYi_KiOYSOVdaGfC1kfUbII0r6Zl2NE1hnU,4208
55
+ uk_bin_collection/uk_bin_collection/councils/BrentCouncil.py,sha256=BsP7V0vezteX0WAxcxqMf3g6ro-J78W6hubefALRMyg,5222
56
56
  uk_bin_collection/uk_bin_collection/councils/BrightonandHoveCityCouncil.py,sha256=k6qt4cds-Ejd97Z-__pw2BYvGVbFdc9SUfF73PPrTNA,5823
57
57
  uk_bin_collection/uk_bin_collection/councils/BristolCityCouncil.py,sha256=nQeRBKrDcZE2m_EzjUBr9dJ5tcUdGcUuA5FcnLkbLr4,5575
58
58
  uk_bin_collection/uk_bin_collection/councils/BroadlandDistrictCouncil.py,sha256=aelqhh503dx6O2EEmC3AT5tnY39Dc53qcouH8T-mek8,7613
@@ -179,6 +179,7 @@ uk_bin_collection/uk_bin_collection/councils/LondonBoroughOfRichmondUponThames.p
179
179
  uk_bin_collection/uk_bin_collection/councils/LondonBoroughRedbridge.py,sha256=A_6Sis5hsF53Th04KeadHRasGbpAm6aoaWJ6X8eC4Y8,6604
180
180
  uk_bin_collection/uk_bin_collection/councils/LondonBoroughSutton.py,sha256=T0gCjpBQ9k3uNNIiJGphNiSXeh2n6bohflg9RwbL3NA,2565
181
181
  uk_bin_collection/uk_bin_collection/councils/LutonBoroughCouncil.py,sha256=vScUi_R8FnBddii2_zLlZBLxuh85mKmCm8nKW3zxky0,2758
182
+ uk_bin_collection/uk_bin_collection/councils/MaidstoneBoroughCouncil.py,sha256=1YZIliUEX3_gaNJDbdCybxNPwkSz0A58gDAl9kSIHsE,4439
182
183
  uk_bin_collection/uk_bin_collection/councils/MaldonDistrictCouncil.py,sha256=PMVt2XFggttPmbWyrBrHJ-W6R_6-0ux1BkY1kj1IKzg,1997
183
184
  uk_bin_collection/uk_bin_collection/councils/MalvernHillsDC.py,sha256=iQG0EkX2npBicvsGKQRYyBGSBvKVUbKvUvvwrC9xV1A,2100
184
185
  uk_bin_collection/uk_bin_collection/councils/ManchesterCityCouncil.py,sha256=RY301_82z3-xInGai5ocT7rzoV75ATbf0N7uxn8Z9LE,3110
@@ -243,7 +244,7 @@ uk_bin_collection/uk_bin_collection/councils/RochfordCouncil.py,sha256=rfhD66A9H
243
244
  uk_bin_collection/uk_bin_collection/councils/RotherDistrictCouncil.py,sha256=-fdLvtik9ytfwXrrhwWdBxqQOMq2N1pvrIuvShhf8PU,3090
244
245
  uk_bin_collection/uk_bin_collection/councils/RotherhamCouncil.py,sha256=LtMPM8lj5bfReDR4buHEo-aRC_HTBIeo1nf8GE5-R80,1790
245
246
  uk_bin_collection/uk_bin_collection/councils/RoyalBoroughofGreenwich.py,sha256=BZzLmWK_VONOmMpSrLrnKtJaOrrepm6aStfKGVcgf9Y,3487
246
- uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py,sha256=cuoxb1PdKtGvYUvcp2bcj7MWL3r83cOnc66Jx79M3sE,4190
247
+ uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py,sha256=q0zMKJk9lEPFBMShqqcCkhw09cFU-CJPgRYCniL9XXA,5686
247
248
  uk_bin_collection/uk_bin_collection/councils/RunnymedeBoroughCouncil.py,sha256=vmTZfijt9b6sKzRdRwROE94lrMVnqs6kn6tg-xi1jR4,1618
248
249
  uk_bin_collection/uk_bin_collection/councils/RushcliffeBoroughCouncil.py,sha256=nWo8xeER71FEbnMTX8W9bcwZNpLEExWzPvgRT7DmcMc,4221
249
250
  uk_bin_collection/uk_bin_collection/councils/RushmoorCouncil.py,sha256=ZsGnXjoEaOS6U7fI0w7-uqxayAHdNVKsJi2fqIWEls8,3375
@@ -339,8 +340,8 @@ uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py,sha256=I2kBYMlsD4bId
339
340
  uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py,sha256=QD4v4xpsEE0QheR_fGaNOIRMc2FatcUfKkkhAhseyVU,1159
340
341
  uk_bin_collection/uk_bin_collection/create_new_council.py,sha256=m-IhmWmeWQlFsTZC4OxuFvtw5ZtB8EAJHxJTH4O59lQ,1536
341
342
  uk_bin_collection/uk_bin_collection/get_bin_data.py,sha256=YvmHfZqanwrJ8ToGch34x-L-7yPe31nB_x77_Mgl_vo,4545
342
- uk_bin_collection-0.150.1.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
343
- uk_bin_collection-0.150.1.dist-info/METADATA,sha256=5EPNN3fs7XWzZbnRZwzDtpg-L9I_m7TljIQk4ZgjEgc,20914
344
- uk_bin_collection-0.150.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
345
- uk_bin_collection-0.150.1.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
346
- uk_bin_collection-0.150.1.dist-info/RECORD,,
343
+ uk_bin_collection-0.151.0.dist-info/LICENSE,sha256=vABBUOzcrgfaTKpzeo-si9YVEun6juDkndqA8RKdKGs,1071
344
+ uk_bin_collection-0.151.0.dist-info/METADATA,sha256=5SIksvWnLyMwc7YNjzyWRTDxFdUbCbpspDeRWeahvVs,20914
345
+ uk_bin_collection-0.151.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
346
+ uk_bin_collection-0.151.0.dist-info/entry_points.txt,sha256=36WCSGMWSc916S3Hi1ZkazzDKHaJ6CD-4fCEFm5MIao,90
347
+ uk_bin_collection-0.151.0.dist-info/RECORD,,