diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..8d69b25 Binary files /dev/null and b/.DS_Store differ diff --git a/penn/.DS_Store b/penn/.DS_Store new file mode 100644 index 0000000..a9dcd66 Binary files /dev/null and b/penn/.DS_Store differ diff --git a/penn/data/laundry.csv b/penn/data/laundry.csv index 2c528a8..6aeb516 100644 --- a/penn/data/laundry.csv +++ b/penn/data/laundry.csv @@ -1,53 +1,53 @@ -0,Bishop White,Quad,5faec7e9-a4aa-47c2-a514-950c03fac460 -1,Chestnut Butcher,Quad,7dfa4b34-f44a-4a38-a6b9-44cdb968a915 -2,Class of 1928 Fisher,Quad,e6697dca-d164-4980-8843-ea0a29b1cf49 -3,Craig,Quad,37d661ce-3e50-4746-ab68-a5c61cd0bd0a -4,DuBois,DuBois,3ffa8978-e742-4076-9bcb-4a3e5c0eca92 -5,English House,KCEH,b655a5be-1287-4ce2-b693-e9c1ae526f38 -6,Harnwell Floor 02,Harnwell,1c7a9fb3-a938-4756-83c6-42d601d46036 -7,Harnwell Floor 04,Harnwell,fba67cc0-336e-42f7-9603-c0b8a0e5030c -8,Harnwell Floor 06,Harnwell,87195ec7-eb3d-42fd-84aa-d63f4e45e285 -9,Harnwell Floor 08,Harnwell,1bbb2ff6-d5e6-406d-a3a2-96c7972cceeb -10,Harnwell Floor 10,Harnwell,987bf30b-e8e1-4a9e-b842-c9cd8aeafddc -11,Harnwell Floor 12,Harnwell,dcb76f10-0137-4783-8604-bece4111b6dd -12,Harnwell Floor 14,Harnwell,941b2fcb-2b1b-4afd-8e8e-c100fbcbe0f2 -13,Harnwell Floor 16,Harnwell,c74b2798-2d09-42a6-b65c-a5834219be59 -14,Harnwell Floor 18,Harnwell,f30af904-72ad-49f6-aecf-f44c8301fb6b -15,Harnwell Floor 20,Harnwell,80a413fd-e0fa-456d-b922-f1576ded1f98 -16,Harnwell Floor 22,Harnwell,35119e5e-92c0-45fb-bfeb-f2059196f644 -17,Harnwell Floor 24,Harnwell,5880b051-8216-4cf4-92d6-5c7475f43eea -18,Harrison Floor 04,Harrison,447b5682-4c3c-441d-ab49-5f45aee6991f -19,Harrison Floor 06,Harrison,f77f7c68-f719-4843-8987-d64dabc0abff -20,Harrison Floor 08,Harrison,6561bb14-634f-437d-84fd-a0837ef991e7 -21,Harrison Floor 10,Harrison,2dd7a63d-7d13-48e5-b038-98054b4f039f -22,Harrison Floor 12,Harrison,fdb607c7-63eb-4d55-a312-0c16b682cbe7 -23,Harrison Floor 14,Harrison,53fdd440-e887-49e1-9ca9-7bb3cb4ab541 -24,Harrison Floor 16,Harrison,8cedf60a-8f87-4128-89dd-4c75343ca64a -25,Harrison Floor 18,Harrison,116a8d6f-045b-47a5-b3f7-af31f4e661eb -26,Harrison Floor 20,Harrison,f6a8b303-1302-49e6-be53-c8e345316ed8 -27,Harrison Floor 22,Harrison,b21c78af-1ebf-418c-a73b-85dc5ff49763 -28,Harrison Floor 24,Harrison,9b95c471-053c-46ea-bc3b-d23bcad7a3a1 -29,Hill House,Hill,82a00eb7-f70d-4a4c-9f0a-c2dafa4b67ea -30,Magee Amhurst,Quad,f6825dac-5a5a-4e4b-b66f-ea8226cbe78e -31,Mayer,Stouffer,6e3531d1-eebd-48b4-ad04-cf5983d42b02 -32,Morgan,Quad,f249ca9f-ef84-4a35-9477-449b14612057 -33,Rodin Floor 02,Rodin,7f25802d-31ad-4f80-ba26-d68a3f403aa8 -34,Rodin Floor 04,Rodin,49e560fb-c1aa-4c98-a88a-cc9564481ec0 -35,Rodin Floor 06,Rodin,701ce966-aa3c-4063-b3db-548ad89cb643 -36,Rodin Floor 08,Rodin,4998a8a2-fb86-4900-bcb7-9d7cc6d9b938 -37,Rodin Floor 10,Rodin,030c81c4-2300-4e8e-ae3a-303397a2e216 -38,Rodin Floor 12,Rodin,c561f889-5898-41ba-99f5-2e6d4243e4d3 -39,Rodin Floor 14,Rodin,2d211700-5b59-4c61-8922-991c0f7d7c15 -40,Rodin Floor 16,Rodin,a10ede1d-044d-4852-87c7-eba7588c2497 -41,Rodin Floor 18,Rodin,c3d3f9ae-792c-401c-8bd5-8c61fffe2ab1 -42,Rodin Floor 20,Rodin,e88d3561-dce7-4188-89e7-b72cff7d69d6 -43,Rodin Floor 22,Rodin,6b7dcd18-fe4e-4dc2-893f-35f0d7939c3c -44,Rodin Floor 24,Rodin,18397cd6-202e-4680-b82e-33ccd9ded1a7 -45,Sansom East,Sansom,ad980c78-bf6d-429a-9a08-1b0899f83d62 -46,Sansom West,Sansom,d1637690-098b-4eca-b48b-6d137207a38e -47,Stouffer Commons,Stouffer,d4848e7d-fdd0-4faa-b6bd-dc152842cf84 -48,New College House,New College House,14b91b75-563b-4a7f-8b80-4efed338c29b -49,Harrison Floor 02,Harrison,78568718-85eb-420b-bc10-77154a685699 -50,Van Pelt,Gregory,5d9b0588-c987-4d2c-9842-2ce3e9101577 -51,Class of 1925,Gregory,78f20171-ab32-4650-a1ce-28ace7095790 -52,Kings Court,KCEH,fdbd6c5f-cb26-486f-86cc-f0b95a7f2a8a +0,Bishop/White,Quad,5faec7e9-a4aa-47c2-a514-950c03fac460 +1,Chestnut/Butcher,Quad,7dfa4b34-f44a-4a38-a6b9-44cdb968a915 +2,Class of 1928/Fisher,Quad,e6697dca-d164-4980-8843-ea0a29b1cf49 +3,Craig,Quad,37d661ce-3e50-4746-ab68-a5c61cd0bd0a +4,DuBois,DuBois,3ffa8978-e742-4076-9bcb-4a3e5c0eca92 +5,English House,KCEH,b655a5be-1287-4ce2-b693-e9c1ae526f38 +6,Harnwell Floor 02,Harnwell,1c7a9fb3-a938-4756-83c6-42d601d46036 +7,Harnwell Floor 04,Harnwell,fba67cc0-336e-42f7-9603-c0b8a0e5030c +8,Harnwell Floor 06,Harnwell,87195ec7-eb3d-42fd-84aa-d63f4e45e285 +9,Harnwell Floor 08,Harnwell,1bbb2ff6-d5e6-406d-a3a2-96c7972cceeb +10,Harnwell Floor 10,Harnwell,987bf30b-e8e1-4a9e-b842-c9cd8aeafddc +11,Harnwell Floor 12,Harnwell,dcb76f10-0137-4783-8604-bece4111b6dd +12,Harnwell Floor 14,Harnwell,941b2fcb-2b1b-4afd-8e8e-c100fbcbe0f2 +13,Harnwell Floor 16,Harnwell,c74b2798-2d09-42a6-b65c-a5834219be59 +14,Harnwell Floor 18,Harnwell,f30af904-72ad-49f6-aecf-f44c8301fb6b +15,Harnwell Floor 20,Harnwell,80a413fd-e0fa-456d-b922-f1576ded1f98 +16,Harnwell Floor 22,Harnwell,35119e5e-92c0-45fb-bfeb-f2059196f644 +17,Harnwell Floor 24,Harnwell,5880b051-8216-4cf4-92d6-5c7475f43eea +18,Harrison Floor 04,Harrison,447b5682-4c3c-441d-ab49-5f45aee6991f +19,Harrison Floor 06,Harrison,f77f7c68-f719-4843-8987-d64dabc0abff +20,Harrison Floor 08,Harrison,6561bb14-634f-437d-84fd-a0837ef991e7 +21,Harrison Floor 10,Harrison,2dd7a63d-7d13-48e5-b038-98054b4f039f +22,Harrison Floor 12,Harrison,fdb607c7-63eb-4d55-a312-0c16b682cbe7 +23,Harrison Floor 14,Harrison,53fdd440-e887-49e1-9ca9-7bb3cb4ab541 +24,Harrison Floor 16,Harrison,8cedf60a-8f87-4128-89dd-4c75343ca64a +25,Harrison Floor 18,Harrison,116a8d6f-045b-47a5-b3f7-af31f4e661eb +26,Harrison Floor 20,Harrison,f6a8b303-1302-49e6-be53-c8e345316ed8 +27,Harrison Floor 22,Harrison,b21c78af-1ebf-418c-a73b-85dc5ff49763 +28,Harrison Floor 24,Harrison,9b95c471-053c-46ea-bc3b-d23bcad7a3a1 +29,Hill House,Hill,82a00eb7-f70d-4a4c-9f0a-c2dafa4b67ea +30,Magee/Amhurst,Quad,f6825dac-5a5a-4e4b-b66f-ea8226cbe78e +31,Mayer,Stouffer,6e3531d1-eebd-48b4-ad04-cf5983d42b02 +32,Morgan,Quad,f249ca9f-ef84-4a35-9477-449b14612057 +33,Rodin Floor 02,Rodin,7f25802d-31ad-4f80-ba26-d68a3f403aa8 +34,Rodin Floor 04,Rodin,49e560fb-c1aa-4c98-a88a-cc9564481ec0 +35,Rodin Floor 06,Rodin,701ce966-aa3c-4063-b3db-548ad89cb643 +36,Rodin Floor 08,Rodin,4998a8a2-fb86-4900-bcb7-9d7cc6d9b938 +37,Rodin Floor 10,Rodin,030c81c4-2300-4e8e-ae3a-303397a2e216 +38,Rodin Floor 12,Rodin,c561f889-5898-41ba-99f5-2e6d4243e4d3 +39,Rodin Floor 14,Rodin,2d211700-5b59-4c61-8922-991c0f7d7c15 +40,Rodin Floor 16,Rodin,a10ede1d-044d-4852-87c7-eba7588c2497 +41,Rodin Floor 18,Rodin,c3d3f9ae-792c-401c-8bd5-8c61fffe2ab1 +42,Rodin Floor 20,Rodin,e88d3561-dce7-4188-89e7-b72cff7d69d6 +43,Rodin Floor 22,Rodin,6b7dcd18-fe4e-4dc2-893f-35f0d7939c3c +44,Rodin Floor 24,Rodin,18397cd6-202e-4680-b82e-33ccd9ded1a7 +45,Sansom East,Sansom,ad980c78-bf6d-429a-9a08-1b0899f83d62 +46,Sansom West,Sansom,d1637690-098b-4eca-b48b-6d137207a38e +47,Stouffer Commons,Stouffer,d4848e7d-fdd0-4faa-b6bd-dc152842cf84 +48,New College House,New College House,14b91b75-563b-4a7f-8b80-4efed338c29b +49,Harrison Floor 02,Harrison,78568718-85eb-420b-bc10-77154a685699 +50,Van Pelt,Gregory,5d9b0588-c987-4d2c-9842-2ce3e9101577 +51,Class of 1925,Gregory,78f20171-ab32-4650-a1ce-28ace7095790 +52,Kings Court,KCEH,fdbd6c5f-cb26-486f-86cc-f0b95a7f2a8a \ No newline at end of file diff --git a/penn/laundry.py b/penn/laundry.py index 817438e..ced5ba9 100644 --- a/penn/laundry.py +++ b/penn/laundry.py @@ -5,7 +5,7 @@ from bs4 import BeautifulSoup LAUNDRY_DOMAIN = os.environ.get("LAUNDRY_DOMAIN", "suds.kite.upenn.edu") -ALL_URL = 'http://{}/?location='.format(LAUNDRY_DOMAIN) +ALL_URL = 'http://{}/'.format(LAUNDRY_DOMAIN) USAGE_BASE_URL = 'https://www.laundryalert.com/cgi-bin/penn6389/LMRoomUsage?CallingPage=LMRoom&Password=penn6389&Halls=' @@ -82,38 +82,61 @@ def parse_a_hall(self, hall): :type hall: int """ if hall not in self.hall_to_link: - return None # change to to empty json idk - page = requests.get(self.hall_to_link[hall], timeout=60) + return None + + return self.parse_halls([hall])[0] + + def parse_halls(self, lhall): + """Return list of names, hall numbers, and the washers/dryers available for a list of halls. + + :param halls: + The IDs of the halls to retrieve data for. + :type halls: list(int) + """ + lmachines = [] + page = requests.get(ALL_URL) soup = BeautifulSoup(page.content, 'html.parser') soup.prettify() - washers = {"open": 0, "running": 0, "out_of_order": 0, "offline": 0, "time_remaining": []} - dryers = {"open": 0, "running": 0, "out_of_order": 0, "offline": 0, "time_remaining": []} - - detailed = [] - - rows = soup.find_all('tr') - for row in rows: - cols = row.find_all('td') - if len(cols) > 1: - machine_type = cols[1].getText() - if machine_type == "Washer": - washers = Laundry.update_machine_object(cols, washers) - elif machine_type == "Dryer": - dryers = Laundry.update_machine_object(cols, dryers) - if machine_type in ["Washer", "Dryer"]: - try: - time = int(cols[3].getText().split(" ")[0]) - except ValueError: - time = 0 - detailed.append({ - "id": int(cols[0].getText().split(" ")[1][1:]), - "type": cols[1].getText().lower(), - "status": cols[2].getText(), - "time_remaining": time - }) - - machines = {"washers": washers, "dryers": dryers, "details": detailed} - return machines + for hall in lhall: + if hall not in self.id_to_hall: + lmachines.append(None) + else: + hall = self.id_to_hall[hall] + washers = {"open": 0, "running": 0, "out_of_order": 0, "offline": 0, "time_remaining": []} + dryers = {"open": 0, "running": 0, "out_of_order": 0, "offline": 0, "time_remaining": []} + found_hall = False + detailed = [] + + rows = soup.find_all('tr') + for row in rows: + cols = row.find_all('td') + if len(cols) == 1 and len(cols[0].find_all('center')) == 1 and \ + len(cols[0].find_all('center')[0].find_all('h2')) == 1: # Title element + if(cols[0].find_all('center')[0].find_all('h2')[0].find_all('a')[0].getText() == hall): # Check if found correct hall + found_hall = True + else: + found_hall = False + elif len(cols) == 5 and cols[2]['class'][0] == 'status' and found_hall: # Content element for relevant hall + machine_type = cols[1].getText() + if machine_type == "Washer": + washers = Laundry.update_machine_object(cols, washers) + elif machine_type == "Dryer": + dryers = Laundry.update_machine_object(cols, dryers) + if machine_type in ["Washer", "Dryer"]: + try: + time = int(cols[3].getText().split(" ")[0]) + except ValueError: + time = 0 + detailed.append({ + "id": int(cols[0].getText().split(" ")[1][1:]), + "type": cols[1].getText().lower(), + "status": cols[2].getText(), + "time_remaining": time + }) + + machines = {"washers": washers, "dryers": dryers, "details": detailed} + lmachines.append(machines) + return lmachines def all_status(self): """Return names, hall numbers, and the washers/dryers available for all @@ -121,11 +144,10 @@ def all_status(self): >>> all_laundry = l.all_status() """ - laundry_rooms = {} - for room in self.hall_to_link: - laundry_rooms[room] = self.parse_a_hall(room) + hall_names = list(self.id_to_hall) + hall_values = self.parse_halls(hall_names) - return laundry_rooms + return {k: v for k, v in zip(hall_names, hall_values)} def hall_status(self, hall_id): """Return the status of each specific washer/dryer in a particular @@ -149,35 +171,3 @@ def hall_status(self, hall_id): 'hall_name': hall_name, 'location': location } - - def machine_usage(self, hall_no): - """Returns the average usage of laundry machines every hour - for a given hall. - - The usages are returned in a dictionary, with the key being - the day of the week, and the value being an array listing the usages - per hour. - - :param hall_no: - integer corresponding to the id number for the hall. Thus number - is returned as part of the all_status call. - - >>> english_house = l.machine_usage(2) - """ - - try: - num = int(hall_no) - except ValueError: - raise ValueError("Room Number must be integer") - r = requests.get(USAGE_BASE_URL + str(num), timeout=60) - parsed = BeautifulSoup(r.text, 'html5lib') - usage_table = parsed.find_all('table', width='504px')[0] - rows = usage_table.find_all('tr') - usages = {} - for i, row in enumerate(rows): - day = [] - hours = row.find_all('td') - for hour in hours: - day.append(self.busy_dict[str(hour['class'][0])]) - usages[self.days[i]] = day - return usages diff --git a/tests/laundry_test.py b/tests/laundry_test.py index 0244657..6864c30 100644 --- a/tests/laundry_test.py +++ b/tests/laundry_test.py @@ -40,11 +40,3 @@ def test_single_hall(self): ok_('id' in machine) ok_('type' in machine) ok_('status' in machine) - - def test_usage(self): - for i in range(10): - data = self.laundry.machine_usage(i) - for j in data: - ok_(j in self.laundry.days) - for k in data[j]: - ok_(k in self.laundry.busy_dict.values())