2020from __future__ import annotations
2121
2222import requests
23- from html .parser import HTMLParser
24- from typing import Any
23+ from typing import Any , NamedTuple
2524
2625LIBRARY_URL = (
2726 "https://pitt.primo.exlibrisgroup.com/primaws/rest/pub/pnxs"
3130 "&scope=MyInst_and_CI&searchInFulltextUserSelection=false&skipDelivery=Y&sort=rank&tab=Everything"
3231 "&vid=01PITT_INST:01PITT_INST"
3332)
34-
3533STUDY_ROOMS_URL = (
3634 "https://pitt.libcal.com/spaces/bookings/search"
3735 "?lid=917&gid=1558&eid=0&seat=0&d=1&customDate=&q=&daily=0&draw=1&order%5B0%5D%5Bcolumn%5D=1&order%5B0%5D%5Bdir%5D=asc"
3836 "&start=0&length=25&search%5Bvalue%5D=&_=1717907260661"
3937)
4038
41-
4239QUERY_START = "&q=any,contains,"
4340
4441sess = requests .session ()
4542
4643
47- class HTMLStrip (HTMLParser ):
48- def __init__ (self ):
49- super ().__init__ ()
50- self .reset ()
51- self .data = []
44+ class Document (NamedTuple ):
45+ # Field names must exactly match key names in JSON data
46+ title : list [str ] | None = None
47+ language : list [str ] | None = None
48+ subject : list [str ] | None = None
49+ format : list [str ] | None = None
50+ type : list [str ] | None = None
51+ isbns : list [str ] | None = None
52+ description : list [str ] | None = None
53+ publisher : list [str ] | None = None
54+ edition : list [str ] | None = None
55+ genre : list [str ] | None = None
56+ place : list [str ] | None = None
57+ creator : list [str ] | None = None
58+ version : list [str ] | None = None
59+ creationdate : list [str ] | None = None
60+
61+
62+ class QueryResult (NamedTuple ):
63+ num_results : int
64+ num_pages : int
65+ docs : list [Document ]
5266
53- def handle_data (self , d : str ) -> None :
54- self .data .append (d )
5567
56- def get_data (self ) -> str :
57- return "" .join (self .data )
68+ class Reservation (NamedTuple ):
69+ room : str
70+ reserved_from : str
71+ reserved_until : str
5872
5973
60- def get_documents (query : str , page : int = 1 ) -> dict [ str , Any ] :
74+ def get_documents (query : str ) -> QueryResult :
6175 """Return ten resource results from the specified page"""
6276 parsed_query = query .replace (" " , "+" )
6377 full_query = LIBRARY_URL + QUERY_START + parsed_query
6478 resp = sess .get (full_query )
6579 resp_json = resp .json ()
6680
67- results = _extract_results (resp_json )
81+ results = QueryResult (
82+ num_results = resp_json ["info" ]["total" ],
83+ num_pages = resp_json ["info" ]["last" ],
84+ docs = _filter_documents (resp_json ["docs" ]),
85+ )
6886 return results
6987
7088
71- def get_document_by_bookmark (bookmark : str ) -> dict [ str , Any ] :
89+ def get_document_by_bookmark (bookmark : str ) -> QueryResult :
7290 """Return resource referenced by bookmark"""
7391 payload = {"bookMark" : bookmark }
7492 resp = sess .get (LIBRARY_URL , params = payload )
@@ -78,92 +96,50 @@ def get_document_by_bookmark(bookmark: str) -> dict[str, Any]:
7896 for error in resp_json .get ("errors" ):
7997 if error ["code" ] == "invalid.bookmark.format" :
8098 raise ValueError ("Invalid bookmark" )
81- results = _extract_results (resp_json )
82- return results
83-
84-
85- def _strip_html (html : str ) -> str :
86- strip = HTMLStrip ()
87- strip .feed (html )
88- return strip .get_data ()
89-
90-
91- def _extract_results (json : dict [str , Any ]) -> dict [str , Any ]:
92- results = {
93- "total_results" : json ["info" ]["total" ],
94- "pages" : json ["info" ]["last" ],
95- "docs" : _extract_documents (json ["docs" ]),
96- }
99+ results = QueryResult (
100+ num_results = resp_json ["info" ]["total" ],
101+ num_pages = resp_json ["info" ]["last" ],
102+ docs = _filter_documents (resp_json ["docs" ]),
103+ )
97104 return results
98105
99106
100- def _extract_documents (documents : list [dict [str , Any ]]) -> list [dict [str , Any ]]:
101- new_docs = []
102- keep_keys = {
103- "title" ,
104- "language" ,
105- "subject" ,
106- "format" ,
107- "type" ,
108- "isbns" ,
109- "description" ,
110- "publisher" ,
111- "edition" ,
112- "genre" ,
113- "place" ,
114- "creator" ,
115- "edition" ,
116- "version" ,
117- "creationdate" ,
118- }
107+ def _filter_documents (documents : list [dict [str , Any ]]) -> list [Document ]:
108+ new_docs : list [Document ] = []
119109
120110 for doc in documents :
121- new_doc = {}
122- for key in set (doc ["pnx" ]["display" ].keys ()) & keep_keys :
123- new_doc [key ] = doc ["pnx" ]["display" ][key ]
124- new_docs .append (new_doc )
111+ filtered_doc = {key : vals for key , vals in doc ["pnx" ]["display" ].items () if key in Document ._fields }
112+ new_docs .append (Document (** filtered_doc ))
125113
126114 return new_docs
127115
128116
129- def _extract_facets (facet_fields : list [dict [str , Any ]]) -> dict [str , list [dict [str , Any ]]]:
130- facets : dict [str , list [dict [str , Any ]]] = {}
131- for facet in facet_fields :
132- facets [facet ["display_name" ]] = []
133- for count in facet ["counts" ]:
134- facets [facet ["display_name" ]].append ({"value" : count ["value" ], "count" : count ["count" ]})
135-
136- return facets
137-
138-
139- def hillman_total_reserved () -> dict [str , int ]:
117+ def hillman_total_reserved () -> int :
140118 """Returns a simple count dictionary of the total amount of reserved rooms appointments"""
141- count = {}
142119 resp = requests .get (STUDY_ROOMS_URL )
143- resp = resp .json ()
144- # Total records is kept track of by default in the JSON
145- total_records = resp ["recordsTotal" ]
120+ resp_json = resp .json ()
121+ total_records : int = resp_json ["recordsTotal" ] # Total records is kept track of by default in the JSON
146122
147123 # Note: this must align with the amount of entries in reserved times function; renamed for further clarification
148- count ["Total Hillman Reservations" ] = total_records
149- return count
124+ return total_records
150125
151126
152- def reserved_hillman_times () -> list [dict [ str , str | list [ str ]] ]:
127+ def reserved_hillman_times () -> list [Reservation ]:
153128 """Returns a list of dictionaries of reserved rooms in Hillman with their respective times"""
154129 resp = requests .get (STUDY_ROOMS_URL )
155- resp = resp .json ()
156- data = resp ["data" ]
130+ resp_json = resp .json ()
131+ data = resp_json ["data" ]
157132
158133 if data is None :
159134 return []
160135
161136 # Note: there can be multiple reservations in the same room, so we must use a list of maps and not a singular map
162137 bookings = [
163- {
164- "Room" : reservation ["itemName" ],
165- "Reserved" : [reservation ["from" ], reservation ["to" ]],
166- }
138+ Reservation (
139+ room = reservation ["itemName" ],
140+ reserved_from = reservation ["from" ],
141+ reserved_until = reservation ["to" ],
142+ )
167143 for reservation in data
168144 ]
169145 return bookings
0 commit comments