diff --git a/CHANGES.rst b/CHANGES.rst index a106902..40e1bb4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,27 @@ Changes ******* +2.16.0 +====== + +Application Changes +------------------- + +* Add ``retrieve_random()``, ``retrieve_random_id()``, ``retrieve_random_slug()``, ``retrieve_random_date()`` and ``retrieve_random_details()`` to the following classes that mirror the corresponding feature in the `Wait Wait Stats Page`_ + + * :py:class:`wwdtm.guest.Guest` + * :py:class:`wwdtm.host.Host` + * :py:class:`wwdtm.location.Location` + * :py:class:`wwdtm.panelist.Panelist` + * :py:class:`wwdtm.scorekeeper.Scorekeeper` + * :py:class:`wwdtm.show.Show` + +Development Changes +------------------- + +* Add corresponding tests for the new series of retrieve random items +* Fixed typos in docstrings or testing assertion messages + 2.15.0 ====== @@ -588,3 +609,6 @@ Application Changes * More detailed documentation, including changes from the previous library to ``wwdtm`` version 2, is available under ``docs/`` and is published at: https://docs.wwdt.me/en/latest/migrating/index.html + + +.. _Wait Wait Stats Page: https://stats.wwdt.me/ \ No newline at end of file diff --git a/tests/guest/test_guest_guest.py b/tests/guest/test_guest_guest.py index e83a85d..4cfc6b9 100644 --- a/tests/guest/test_guest_guest.py +++ b/tests/guest/test_guest_guest.py @@ -102,7 +102,7 @@ def test_guest_retrieve_details_by_id(guest_id: int): info = guest.retrieve_details_by_id(guest_id) assert info, f"Guest ID {guest_id} not found" - assert "name" in info, f"'name' attribute was returned for ID {guest_id}" + assert "name" in info, f"'name' attribute was not returned for ID {guest_id}" assert "appearances" in info, f"'appearances' was not returned for ID {guest_id}" @@ -120,3 +120,40 @@ def test_guest_guest_retrieve_details_by_slug(guest_slug: str): assert "appearances" in info, ( f"'appearances' was not returned for slug {guest_slug}" ) + + +def test_guest_retrieve_random_id() -> None: + """Testing for :py:meth`wwdtm.guest.Guest.retrieve_random_id`.""" + guest = Guest(connect_dict=get_connect_dict()) + _id = guest.retrieve_random_id() + + assert _id, "Returned random guest ID is not valid" + assert isinstance(_id, int), "Returned random guest ID is not an integer" + + +def test_guest_retrieve_random_slug() -> None: + """Testing for :py:meth`wwdtm.guest.Guest.retrieve_random_slug`.""" + guest = Guest(connect_dict=get_connect_dict()) + _slug = guest.retrieve_random_slug() + + assert _slug, "Returned random guest slug string is not valid" + assert isinstance(_slug, str), "Returned random guest slug string is not a string" + + +def test_guest_retrieve_random() -> None: + """Testing for :py:meth:`wwdtm.guest.Guest.retrieve_random`.""" + guest = Guest(connect_dict=get_connect_dict()) + info = guest.retrieve_random() + + assert info, "Random guest not found" + assert "name" in info, "'name' attribute was not returned for a random guest" + + +def test_guest_retrieve_random_details() -> None: + """Testing for :py:meth:`wwdtm.guest.Guest.retrieve_random_details`.""" + guest = Guest(connect_dict=get_connect_dict()) + info = guest.retrieve_random_details() + + assert info, "Random guest not found" + assert "name" in info, "'name' attribute was not returned for a random guest" + assert "appearances" in info, "'appearances' was not returned for a random guest" diff --git a/tests/host/test_host_host.py b/tests/host/test_host_host.py index 84698a8..6ca5c98 100644 --- a/tests/host/test_host_host.py +++ b/tests/host/test_host_host.py @@ -132,3 +132,44 @@ def test_host_retrieve_details_by_slug(host_slug: str): assert "slug" in info, f"'slug' was not returned for ID {host_slug}" assert "pronouns" in info, f"'pronouns' was not returned for ID {host_slug}" assert "appearances" in info, f"'appearances' was not returned for slug {host_slug}" + + +def test_host_retrieve_random_id() -> None: + """Testing for :py:meth`wwdtm.host.Host.retrieve_random_id`.""" + host = Host(connect_dict=get_connect_dict()) + _id = host.retrieve_random_id() + + assert _id, "Returned random host ID is not valid" + assert isinstance(_id, int), "Returned random host ID is not an integer" + + +def test_host_retrieve_random_slug() -> None: + """Testing for :py:meth`wwdtm.host.Host.retrieve_random_slug`.""" + host = Host(connect_dict=get_connect_dict()) + _slug = host.retrieve_random_slug() + + assert _slug, "Returned random host slug string is not valid" + assert isinstance(_slug, str), "Returned random host slug string is not a string" + + +def test_host_retrieve_random() -> None: + """Testing for :py:meth:`wwdtm.host.Host.retrieve_random`.""" + host = Host(connect_dict=get_connect_dict()) + info = host.retrieve_random() + + assert info, "Random host not found" + assert "name" in info, "'name' attribute was not returned for a random host" + assert "slug" in info, "'slug' was not returned for a random host" + assert "pronouns" in info, "'pronouns' was not returned for a random host" + + +def test_host_retrieve_random_details() -> None: + """Testing for :py:meth:`wwdtm.host.Host.retrieve_random_details`.""" + host = Host(connect_dict=get_connect_dict()) + info = host.retrieve_random_details() + + assert info, "Random host not found" + assert "name" in info, "'name' attribute was not returned for a random host" + assert "slug" in info, "'slug' was not returned for a random host" + assert "pronouns" in info, "'pronouns' was not returned for a random host" + assert "appearances" in info, "'appearances' was not returned for a random host" diff --git a/tests/location/test_location_location.py b/tests/location/test_location_location.py index 886639d..405b789 100644 --- a/tests/location/test_location_location.py +++ b/tests/location/test_location_location.py @@ -36,16 +36,16 @@ def test_location_retrieve_all(): assert locations, "No locations could be retrieved" assert "id" in locations[0], "'id' was not returned for the first list item" assert "venue" in locations[0], "'venue' was not returned for the first list item" - assert ( - "coordinates" in locations[0] - ), "'coordinates' was not returned for the first list item" + assert "coordinates" in locations[0], ( + "'coordinates' was not returned for the first list item" + ) if locations[0]["coordinates"]: - assert ( - "latitude" in locations[0]["coordinates"] - ), "'latitude' was not returned for the first list item" - assert ( - "longitude" in locations[0]["coordinates"] - ), "'longitude' was not returned for the first list item" + assert "latitude" in locations[0]["coordinates"], ( + "'latitude' was not returned for the first list item" + ) + assert "longitude" in locations[0]["coordinates"], ( + "'longitude' was not returned for the first list item" + ) def test_location_retrieve_all_details(): @@ -56,19 +56,19 @@ def test_location_retrieve_all_details(): assert locations, "No locations could be retrieved" assert "id" in locations[0], "'id' was not returned for first list item" assert "venue" in locations[0], "'venue' was not returned for the first list item" - assert ( - "coordinates" in locations[0] - ), "'coordinates' was not returned for the first list item" + assert "coordinates" in locations[0], ( + "'coordinates' was not returned for the first list item" + ) if locations[0]["coordinates"]: - assert ( - "latitude" in locations[0]["coordinates"] - ), "'latitude' was not returned for the first list item" - assert ( - "longitude" in locations[0]["coordinates"] - ), "'longitude' was not returned for the first list item" - assert ( - "recordings" in locations[0] - ), "'recordings' was not returned for the first list item" + assert "latitude" in locations[0]["coordinates"], ( + "'latitude' was not returned for the first list item" + ) + assert "longitude" in locations[0]["coordinates"], ( + "'longitude' was not returned for the first list item" + ) + assert "recordings" in locations[0], ( + "'recordings' was not returned for the first list item" + ) def test_location_retrieve_all_ids(): @@ -101,12 +101,12 @@ def test_location_retrieve_by_id(location_id: int): assert "venue" in info, f"'venue' was not returned for ID {location_id}" assert "coordinates" in info, f"'coordinates' was not returned for ID {location_id}" if info["coordinates"]: - assert ( - "latitude" in info["coordinates"] - ), f"'latitude' was not returned for ID {location_id}" - assert ( - "longitude" in info["coordinates"] - ), f"'longitude' was not returned for ID {location_id}" + assert "latitude" in info["coordinates"], ( + f"'latitude' was not returned for ID {location_id}" + ) + assert "longitude" in info["coordinates"], ( + f"'longitude' was not returned for ID {location_id}" + ) @pytest.mark.parametrize("location_id", [95, 148]) @@ -122,12 +122,12 @@ def test_location_retrieve_details_by_id(location_id: int): assert "venue" in info, f"'venue' was not returned for ID {location_id}" assert "coordinates" in info, f"'coordinates' was not returned for ID {location_id}" if info["coordinates"]: - assert ( - "latitude" in info["coordinates"] - ), f"'latitude' was not returned for ID {location_id}" - assert ( - "longitude" in info["coordinates"] - ), f"'longitude' was not returned for ID {location_id}" + assert "latitude" in info["coordinates"], ( + f"'latitude' was not returned for ID {location_id}" + ) + assert "longitude" in info["coordinates"], ( + f"'longitude' was not returned for ID {location_id}" + ) assert "recordings" in info, f"'recordings' was not returned for ID {location_id}" @@ -143,16 +143,16 @@ def test_location_retrieve_by_slug(location_slug: str): assert info, f"Location slug {location_slug} not found" assert "venue" in info, f"'venue' was not returned for slug {location_slug}" - assert ( - "coordinates" in info - ), f"'coordinates' was not returned for slug {location_slug}" + assert "coordinates" in info, ( + f"'coordinates' was not returned for slug {location_slug}" + ) if info["coordinates"]: - assert ( - "latitude" in info["coordinates"] - ), f"'latitude' was not returned for slug {location_slug}" - assert ( - "longitude" in info["coordinates"] - ), f"'longitude' was not returned for slug {location_slug}" + assert "latitude" in info["coordinates"], ( + f"'latitude' was not returned for slug {location_slug}" + ) + assert "longitude" in info["coordinates"], ( + f"'longitude' was not returned for slug {location_slug}" + ) @pytest.mark.parametrize("location_slug", ["the-chicago-theatre-chicago-il"]) @@ -167,19 +167,19 @@ def test_location_retrieve_details_by_slug(location_slug: str): assert info, f"Location slug {location_slug} not found" assert "venue" in info, f"'venue' was not returned for slug {location_slug}" - assert ( - "coordinates" in info - ), f"'coordinates' was not returned for slug {location_slug}" + assert "coordinates" in info, ( + f"'coordinates' was not returned for slug {location_slug}" + ) if info["coordinates"]: - assert ( - "latitude" in info["coordinates"] - ), f"'latitude' was not returned for slug {location_slug}" - assert ( - "longitude" in info["coordinates"] - ), f"'longitude' was not returned for slug {location_slug}" - assert ( - "recordings" in info - ), f"'recordings' was not returned for slug {location_slug}" + assert "latitude" in info["coordinates"], ( + f"'latitude' was not returned for slug {location_slug}" + ) + assert "longitude" in info["coordinates"], ( + f"'longitude' was not returned for slug {location_slug}" + ) + assert "recordings" in info, ( + f"'recordings' was not returned for slug {location_slug}" + ) def test_location_retrieve_postal_abbreviations(): @@ -189,6 +189,45 @@ def test_location_retrieve_postal_abbreviations(): assert abbreviations, "Postal abbreviations not returned" assert "OR" in abbreviations, "Postal abbreviation 'OR' not found" - assert ( - "name" in abbreviations["OR"] - ), "Postal abbreviation 'OR' does not contain a valid name" + assert "name" in abbreviations["OR"], ( + "Postal abbreviation 'OR' does not contain a valid name" + ) + + +def test_location_retrieve_random_id() -> None: + """Testing for :py:meth`wwdtm.location.Location.retrieve_random_id`.""" + location = Location(connect_dict=get_connect_dict()) + _id = location.retrieve_random_id() + + assert _id, "Returned random location ID is not valid" + assert isinstance(_id, int), "Returned random location ID is not an integer" + + +def test_location_retrieve_random_slug() -> None: + """Testing for :py:meth`wwdtm.location.Location.retrieve_random_slug`.""" + location = Location(connect_dict=get_connect_dict()) + _slug = location.retrieve_random_slug() + + assert _slug, "Returned random location slug string is not valid" + assert isinstance(_slug, str), ( + "Returned random location slug string is not a string" + ) + + +def test_location_retrieve_random() -> None: + """Testing for :py:meth:`wwdtm.location.Location.retrieve_random`.""" + location = Location(connect_dict=get_connect_dict()) + info = location.retrieve_random() + + assert info, "Random location not found" + assert "venue" in info, "'venue' attribute was not returned for a random location" + + +def test_location_retrieve_random_details() -> None: + """Testing for :py:meth:`wwdtm.host.Location.retrieve_random_details`.""" + location = Location(connect_dict=get_connect_dict()) + info = location.retrieve_random_details() + + assert info, "Random location not found" + assert "venue" in info, "'venue' attribute was not returned for a random location" + assert "coordinates" in info, "'coordinates' was not returned for a random location" diff --git a/tests/panelist/test_panelist_panelist.py b/tests/panelist/test_panelist_panelist.py index a8b7f95..ee2b85e 100644 --- a/tests/panelist/test_panelist_panelist.py +++ b/tests/panelist/test_panelist_panelist.py @@ -158,3 +158,46 @@ def test_panelist_retrieve_details_by_slug( assert "appearances" in info, ( f"'appearances' was not returned for slug {panelist_slug}" ) + + +def test_panelist_retrieve_random_id() -> None: + """Testing for :py:meth`wwdtm.panelist.Panelist.retrieve_random_id`.""" + panelist = Panelist(connect_dict=get_connect_dict()) + _id = panelist.retrieve_random_id() + + assert _id, "Returned random panelist ID is not valid" + assert isinstance(_id, int), "Returned random panelist ID is not an integer" + + +def test_panelist_retrieve_random_slug() -> None: + """Testing for :py:meth`wwdtm.panelist.Panelist.retrieve_random_slug`.""" + panelist = Panelist(connect_dict=get_connect_dict()) + _slug = panelist.retrieve_random_slug() + + assert _slug, "Returned random panelist slug string is not valid" + assert isinstance(_slug, str), ( + "Returned random panelist slug string is not a string" + ) + + +def test_panelist_retrieve_random() -> None: + """Testing for :py:meth:`wwdtm.panelist.Panelist.retrieve_random`.""" + panelist = Panelist(connect_dict=get_connect_dict()) + info = panelist.retrieve_random() + + assert info, "Random panelist not found" + assert "name" in info, "'name' attribute was not returned for a random panelist" + assert "slug" in info, "'slug' was not returned for a random panelist" + assert "pronouns" in info, "'pronouns' was not returned for a random panelist" + + +def test_panelist_retrieve_random_details() -> None: + """Testing for :py:meth:`wwdtm.panelist.Panelist.retrieve_random_details`.""" + panelist = Panelist(connect_dict=get_connect_dict()) + info = panelist.retrieve_random_details() + + assert info, "Random panelist not found" + assert "name" in info, "'name' attribute was not returned for a random panelist" + assert "slug" in info, "'slug' was not returned for a random panelist" + assert "pronouns" in info, "'pronouns' was not returned for a random panelist" + assert "appearances" in info, "'appearances' was not returned for a random panelist" diff --git a/tests/scorekeeper/test_scorekeeper_scorekeeper.py b/tests/scorekeeper/test_scorekeeper_scorekeeper.py index 2bc807d..625564e 100644 --- a/tests/scorekeeper/test_scorekeeper_scorekeeper.py +++ b/tests/scorekeeper/test_scorekeeper_scorekeeper.py @@ -143,3 +143,48 @@ def test_scorekeeper_retrieve_details_by_slug(scorekeeper_slug: str): assert "appearances" in info, ( f"'appearances' was not returned for slug {scorekeeper_slug}" ) + + +def test_scorekeeper_retrieve_random_id() -> None: + """Testing for :py:meth`wwdtm.scorekeeper.Scorekeeper.retrieve_random_id`.""" + scorekeeper = Scorekeeper(connect_dict=get_connect_dict()) + _id = scorekeeper.retrieve_random_id() + + assert _id, "Returned random scorekeeper ID is not valid" + assert isinstance(_id, int), "Returned random scorekeeper ID is not an integer" + + +def test_scorekeeper_retrieve_random_slug() -> None: + """Testing for :py:meth`wwdtm.scorekeeper.Scorekeeper.retrieve_random_slug`.""" + scorekeeper = Scorekeeper(connect_dict=get_connect_dict()) + _slug = scorekeeper.retrieve_random_slug() + + assert _slug, "Returned random scorekeeper slug string is not valid" + assert isinstance(_slug, str), ( + "Returned random scorekeeper slug string is not a string" + ) + + +def test_scorekeeper_retrieve_random() -> None: + """Testing for :py:meth:`wwdtm.scorekeeper.Scorekeeper.retrieve_random`.""" + scorekeeper = Scorekeeper(connect_dict=get_connect_dict()) + info = scorekeeper.retrieve_random() + + assert info, "Random scorekeeper not found" + assert "name" in info, "'name' attribute was not returned for a random scorekeeper" + assert "slug" in info, "'slug' was not returned for a random scorekeeper" + assert "pronouns" in info, "'pronouns' was not returned for a random scorekeeper" + + +def test_scorekeeper_retrieve_random_details() -> None: + """Testing for :py:meth:`wwdtm.scorekeeper.Scorekeeper.retrieve_random_details`.""" + scorekeeper = Scorekeeper(connect_dict=get_connect_dict()) + info = scorekeeper.retrieve_random_details() + + assert info, "Random scorekeeper not found" + assert "name" in info, "'name' attribute was not returned for a random scorekeeper" + assert "slug" in info, "'slug' was not returned for a random scorekeeper" + assert "pronouns" in info, "'pronouns' was not returned for a random scorekeeper" + assert "appearances" in info, ( + "'appearances' was not returned for a random scorekeeper" + ) diff --git a/tests/show/test_show_show.py b/tests/show/test_show_show.py index 2a70e81..1e187a0 100644 --- a/tests/show/test_show_show.py +++ b/tests/show/test_show_show.py @@ -511,3 +511,40 @@ def test_show_retrieve_years(): assert years, "No years could be retrieved" assert isinstance(years[0], int), "First list item is not a number" + + +def test_show_retrieve_random_id() -> None: + """Testing for :py:meth`wwdtm.show.Show.retrieve_random_id`.""" + show = Show(connect_dict=get_connect_dict()) + _id = show.retrieve_random_id() + + assert _id, "Returned random show ID is not valid" + assert isinstance(_id, int), "Returned random show ID is not an integer" + + +def test_show_retrieve_random_date() -> None: + """Testing for :py:meth`wwdtm.show.Show.retrieve_random_date`.""" + show = Show(connect_dict=get_connect_dict()) + _date = show.retrieve_random_date() + + assert _date, "Returned random show date string is not valid" + assert isinstance(_date, str), "Returned random show date string is not a string" + + +def test_show_retrieve_random() -> None: + """Testing for :py:meth:`wwdtm.show.Show.retrieve_random`.""" + show = Show(connect_dict=get_connect_dict()) + info = show.retrieve_random() + + assert info, "Random show not found" + assert "date" in info, "'date' was not returned for a random show" + + +def test_show_retrieve_random_details() -> None: + """Testing for :py:meth:`wwdtm.panelist.Show.retrieve_random_details`.""" + show = Show(connect_dict=get_connect_dict()) + info = show.retrieve_random_details() + + assert info, "Random show not found" + assert "date" in info, "'date' was not returned for a random show" + assert "host" in info, "'host' was not returned for a random show" diff --git a/wwdtm/__init__.py b/wwdtm/__init__.py index 4738d64..42dfded 100644 --- a/wwdtm/__init__.py +++ b/wwdtm/__init__.py @@ -26,7 +26,7 @@ from wwdtm.scorekeeper import Scorekeeper, ScorekeeperAppearances, ScorekeeperUtility from wwdtm.show import Show, ShowInfo, ShowInfoMultiple, ShowUtility -VERSION = "2.15.0" +VERSION = "2.16.0" def database_version( diff --git a/wwdtm/guest/guest.py b/wwdtm/guest/guest.py index d31b605..c925d58 100644 --- a/wwdtm/guest/guest.py +++ b/wwdtm/guest/guest.py @@ -243,3 +243,71 @@ def retrieve_details_by_slug(self, guest_slug: str) -> dict[str, Any]: return {} return self.retrieve_details_by_id(id_) + + def retrieve_random_id(self) -> int: + """Retrieves an ID for a random guest. + + :return: ID for a random guest. + """ + query = """ + SELECT guestid FROM ww_guests + WHERE guestslug <> 'none' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random_slug(self) -> str: + """Retrieves an slug string for a random guest. + + :return: Slug string for a random guest. + """ + query = """ + SELECT guestslug FROM ww_guests + WHERE guestslug <> 'none' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random(self) -> dict[str, int | str]: + """Retrieves information for a random guest. + + :return: A dictionary containing guest ID, name and slug string + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_by_id(guest_id=_id) + + def retrieve_random_details(self) -> dict[str, Any]: + """Retrieves information and appearances for a random guest. + + :return: A dictionary containing guest ID, name, slug string, + list of appearances with show flags, scores and scoring + exceptions + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_details_by_id(guest_id=_id) diff --git a/wwdtm/host/host.py b/wwdtm/host/host.py index 3826ab2..d4440b7 100644 --- a/wwdtm/host/host.py +++ b/wwdtm/host/host.py @@ -288,3 +288,71 @@ def retrieve_details_by_slug(self, host_slug: str) -> dict[str, Any]: return {} return self.retrieve_details_by_id(id_) + + def retrieve_random_id(self) -> int: + """Retrieves an ID for a random host. + + :return: ID for a random host. + """ + query = """ + SELECT hostid FROM ww_hosts + WHERE hostslug <> 'tbd' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random_slug(self) -> str: + """Retrieves an slug string for a random host. + + :return: Slug string for a random host. + """ + query = """ + SELECT hostslug FROM ww_hosts + WHERE hostslug <> 'tbd' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random(self) -> dict[str, Any]: + """Retrieves information for a random host. + + :return: A dictionary containing host ID, name, gender and slug + string + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_by_id(host_id=_id) + + def retrieve_random_details(self) -> dict[str, Any]: + """Retrieves information and appearances for a random host. + + :return: A dictionary containing host ID, name, gender, slug + string and a list of appearances with show flags + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_details_by_id(host_id=_id) diff --git a/wwdtm/location/location.py b/wwdtm/location/location.py index d9c9923..2f2ba61 100644 --- a/wwdtm/location/location.py +++ b/wwdtm/location/location.py @@ -338,7 +338,7 @@ def retrieve_details_by_slug(self, location_slug: str) -> dict[str, Any]: return self.retrieve_details_by_id(id_) def retrieve_postal_abbreviations(self) -> dict[str, dict[str, str]]: - """Retrieves postal abbreviations and corresponding values. + """Retrieves postal abbreviations, corresponding names and countries. :return: A dictionary containing postal abbreviation as keys and corresponding name and country as values. @@ -351,6 +351,7 @@ def retrieve_postal_abbreviations(self) -> dict[str, dict[str, str]]: cursor = self.database_connection.cursor(dictionary=True) cursor.execute(query) results = cursor.fetchall() + cursor.close() if not results: return None @@ -363,3 +364,129 @@ def retrieve_postal_abbreviations(self) -> dict[str, dict[str, str]]: } return abbreviations + + def retrieve_postal_abbreviations_list(self) -> list[dict[str, str]]: + """Retrieves postal abbreviations, corresponding name and countries as a list. + + :return: A list of dictionaries, each containing postal abbreviation, + corresponding name and country. + """ + _postal_abbreviations = self.retrieve_postal_abbreviations() + + if not _postal_abbreviations: + return None + + abbreviations = [] + for abbreviation in _postal_abbreviations: + abbreviations.append( + { + "postal_abbreviation": abbreviation, + "name": _postal_abbreviations[abbreviation]["name"], + "country": _postal_abbreviations[abbreviation]["country"], + } + ) + + return abbreviations + + def retrieve_postal_details_by_abbreviation( + self, + abbreviation: str, + ) -> dict[str, str]: + """Retrieves postal abbreviation information for a given abbreviation. + + :param abbreviation: Postal Abbreviation + :return: A dictionary containing postal abbreviation, + corresponding name, and country. + """ + if not abbreviation: + return None + + query = """ + SELECT postal_abbreviation, name, country + FROM ww_postal_abbreviations + WHERE postal_abbreviation = %s + ORDER BY postal_abbreviation ASC; + """ + cursor = self.database_connection.cursor(dictionary=True) + cursor.execute(query, (abbreviation,)) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return { + "postal_abbreviation": result[ + "postal_abbreviation", + "name" : result["name"], + "country" : result["country"], + ] + } + + def retrieve_random_id(self) -> int: + """Retrieves an ID for a random location. + + :return: ID for a random location. + """ + query = """ + SELECT locationid FROM ww_locations + WHERE locationslug <> 'tbd' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random_slug(self) -> str: + """Retrieves a slug string for a random location. + + :return: Slug string for a random location. + """ + query = """ + SELECT locationslug FROM ww_locations + WHERE locationslug <> 'tbd' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random(self) -> dict[str, int | str]: + """Retrieves information for a random location. + + :return: A dictionary containing location ID, venue, city, state + and slug string + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_by_id(location_id=_id) + + def retrieve_random_details(self) -> dict[str, Any]: + """Retrieves information and recordings for a random location. + + :return: A dictionary containing location ID, venue name, city, + state, slug string and a list of recordings + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_details_by_id(location_id=_id) diff --git a/wwdtm/panelist/panelist.py b/wwdtm/panelist/panelist.py index 8cb9a56..fb9a749 100644 --- a/wwdtm/panelist/panelist.py +++ b/wwdtm/panelist/panelist.py @@ -321,3 +321,71 @@ def retrieve_details_by_slug( return {} return self.retrieve_details_by_id(id_, use_decimal_scores=use_decimal_scores) + + def retrieve_random_id(self) -> int: + """Retrieves an ID for a random panelist. + + :return: ID for a random panelist. + """ + query = """ + SELECT panelistid FROM ww_panelists + WHERE panelistslug <> 'multiple' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random_slug(self) -> str: + """Retrieves an slug string for a random panelist. + + :return: Slug string for a random panelist. + """ + query = """ + SELECT panelistslug FROM ww_panelists + WHERE panelistslug <> 'multiple' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random(self) -> dict[str, Any]: + """Retrieves information for a random panelist. + + :return: A dictionary containing panelist ID, name, slug string + and gender + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_by_id(panelist_id=_id) + + def retrieve_random_details(self) -> dict[str, Any]: + """Retrieves information and appearances for a random panelist. + + :return: A dictionary containing panelist ID, name, slug string, + gender, scoring statistics and appearances + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_details_by_id(panelist_id=_id) diff --git a/wwdtm/scorekeeper/scorekeeper.py b/wwdtm/scorekeeper/scorekeeper.py index ed8f3eb..e0d2c71 100644 --- a/wwdtm/scorekeeper/scorekeeper.py +++ b/wwdtm/scorekeeper/scorekeeper.py @@ -192,8 +192,8 @@ def retrieve_by_id(self, scorekeeper_id: int) -> dict[str, Any]: """Retrieves scorekeeper information. :param scorekeeper_id: Scorekeeper ID - :return: A dictionary containing host ID, name, slug string and - gender + :return: A dictionary containing scorekeeper ID, name, slug + string and gender """ if not valid_int_id(scorekeeper_id): return {} @@ -237,8 +237,8 @@ def retrieve_by_slug(self, scorekeeper_slug: str) -> dict[str, Any]: """Retrieves scorekeeper information. :param scorekeeper_slug: Scorekeeper slug string - :return: A dictionary containing host ID, name, slug string and - gender + :return: A dictionary containing scorekeeper ID, name, slug + string and gender """ try: slug = scorekeeper_slug.strip() @@ -292,3 +292,71 @@ def retrieve_details_by_slug(self, scorekeeper_slug: str) -> dict[str, Any]: return {} return self.retrieve_details_by_id(id_) + + def retrieve_random_id(self) -> int: + """Retrieves an ID for a random scorekeeper. + + :return: ID for a random scorekeeper. + """ + query = """ + SELECT scorekeeperid FROM ww_scorekeepers + WHERE scorekeeperslug <> 'tbd' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random_slug(self) -> str: + """Retrieves an slug string for a random scorekeeper. + + :return: Slug string for a random scorekeeper. + """ + query = """ + SELECT scorekeeperslug FROM ww_scorekeepers + WHERE scorekeeperslug <> 'tbd' + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random(self) -> dict[str, Any]: + """Retrieves information for a random scorekeeper. + + :return: A dictionary containing scorekeeper ID, name, slug + string and gender + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_by_id(scorekeeper_id=_id) + + def retrieve_random_details(self) -> dict[str, Any]: + """Retrieves information and appearances for a random scorekeeper. + + :return: A dictionaries containing scorekeeper ID, name, slug + string, gender and a list of appearances with show flags + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_details_by_id(scorekeeper_id=_id) diff --git a/wwdtm/show/show.py b/wwdtm/show/show.py index d79f050..6b9a638 100644 --- a/wwdtm/show/show.py +++ b/wwdtm/show/show.py @@ -972,6 +972,76 @@ def retrieve_months_by_year(self, year: int) -> list[int]: return [v[0] for v in results] + def retrieve_random_id(self) -> int: + """Retrieves an ID for a random show. + + :return: ID for a random show. + """ + query = """ + SELECT showid FROM ww_shows + WHERE showdate <= NOW() + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0] + + def retrieve_random_date(self) -> str: + """Retrieves a date for a random show. + + :return: show date string for a random show, in YYYY-MM-DD format. + """ + query = """ + SELECT showdate FROM ww_shows + WHERE showdate <= NOW() + ORDER BY RAND() + LIMIT 1; + """ + cursor = self.database_connection.cursor(dictionary=False) + cursor.execute(query) + result = cursor.fetchone() + cursor.close() + + if not result: + return None + + return result[0].isoformat() + + def retrieve_random(self) -> dict[str, Any]: + """Retrieves information for a random show. + + :return: A dictionary containing show ID, show date, Best Of + show flag, repeat show ID (if applicable) and show URL at + NPR.org + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_by_id(show_id=_id) + + def retrieve_random_details(self) -> dict[str, Any]: + """Retrieves information and appearances for a random show. + + :return: A dictionary containing show ID, show date, Best Of + show flag, repeat show ID (if applicable), show URL at + NPR.org, host, scorekeeper, location, panelists and guests + """ + _id = self.retrieve_random_id() + + if not _id: + return None + + return self.retrieve_details_by_id(show_id=_id) + def retrieve_recent( self, include_days_ahead: int = 7,