From 4ea9a16e140c1be99684d62435ae743f4da1ea23 Mon Sep 17 00:00:00 2001 From: BLI Date: Wed, 17 Mar 2021 11:31:15 -0400 Subject: [PATCH 1/2] Inserted comments and made minor changes --- COVID19Py/covid19.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/COVID19Py/covid19.py b/COVID19Py/covid19.py index a68faa7..c6f7177 100644 --- a/COVID19Py/covid19.py +++ b/COVID19Py/covid19.py @@ -67,7 +67,7 @@ def _getSources(self): def _request(self, endpoint, params=None): if params is None: params = {} - response = requests.get(self.url + endpoint, {**params, "source":self.data_source}) + response = requests.get(self.url + endpoint, {*params, "source":self.data_source}) #fixed a syntax error (originally **) response.raise_for_status() return response.json() @@ -79,9 +79,9 @@ def getLatestChanges(self): changes = None if self.previousData: changes = { - "confirmed": self.latestData["latest"]["confirmed"] - self.latestData["latest"]["confirmed"], - "deaths": self.latestData["latest"]["deaths"] - self.latestData["latest"]["deaths"], - "recovered": self.latestData["latest"]["recovered"] - self.latestData["latest"]["recovered"], + "confirmed": self.latestData["latest"]["confirmed"] - self.previousData["latest"]["confirmed"], #changed from latestData to previousData + "deaths": self.latestData["latest"]["deaths"] - self.previousData["latest"]["deaths"], #changed from latestData to previousData + "recovered": self.latestData["latest"]["recovered"] - self.previousData["latest"]["recovered"], #changed from latestData to previousData } else: changes = { From a569f727cc73d210893dd07e75b09418fef5d7a1 Mon Sep 17 00:00:00 2001 From: BLI Date: Wed, 17 Mar 2021 13:39:57 -0400 Subject: [PATCH 2/2] Aggregation Pull Request #1 --- COVID19Py/covid19.py | 111 ++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/COVID19Py/covid19.py b/COVID19Py/covid19.py index c6f7177..dbe4cec 100644 --- a/COVID19Py/covid19.py +++ b/COVID19Py/covid19.py @@ -2,15 +2,14 @@ import requests import json -class COVID19(object): - default_url = "https://covid-tracker-us.herokuapp.com" +#class acting as an aggregate for all operations related to setting up the user's data retrieval request +class UserRequestSetup(object): + __default_url = "https://covid-tracker-us.herokuapp.com" url = "" data_source = "" - previousData = None - latestData = None _valid_data_sources = [] - mirrors_source = "https://raw.github.com/Kamaropoulos/COVID19Py/master/mirrors.json" + __mirrors_source = "https://raw.github.com/Kamaropoulos/COVID19Py/master/mirrors.json" mirrors = None def __init__(self, url="https://covid-tracker-us.herokuapp.com", data_source='jhu'): @@ -49,6 +48,36 @@ def __init__(self, url="https://covid-tracker-us.herokuapp.com", data_source='jh raise ValueError("Invalid data source. Expected one of: %s" % self._valid_data_sources) self.data_source = data_source + + def _getSources(self): + response = requests.get(self.url + "/v2/sources") + response.raise_for_status() + return response.json()["sources"] + + + #originally _request, underscore removed as it is now referred to by class COVID19DataRetrieval and requires access. Underscore indicates protected status + def request(self, endpoint, params=None): + if params is None: + params = {} + response = requests.get(self.url + endpoint, {*params, "source": self.data_source}) #fixed a syntax error (originally **) + response.raise_for_status() + return response.json() + + + +#class acting as an aggregate for all data retrieval operations +class COVID19DataRetrieval(object): + #originally variables from the class COVID19. Variables are only used in the operations contained within the COVIDDataRetrieval class, hence they were moved here + __previousData = None + __latestData = None + + + #"constructor" method that initializes data members of the class, where applicable + def __init__(self, userrequestsetup) + self.userrequestsetup = userrequestsetup #enables/allows us to access methods in the UserRequestSetup class, mainly the request method + + + #updates to latest data def _update(self, timelines): latest = self.getLatest() locations = self.getLocations(timelines) @@ -59,22 +88,27 @@ def _update(self, timelines): "locations": locations } - def _getSources(self): - response = requests.get(self.url + "/v2/sources") - response.raise_for_status() - return response.json()["sources"] - def _request(self, endpoint, params=None): - if params is None: - params = {} - response = requests.get(self.url + endpoint, {*params, "source":self.data_source}) #fixed a syntax error (originally **) - response.raise_for_status() - return response.json() +############################# +# Generalized data searches +############################# + #get all data at once def getAll(self, timelines=False): self._update(timelines) return self.latestData + + #gets the latest COVID-19 case data + def getLatest(self) -> List[Dict[str, int]]: + """ + :return: The latest amount of total confirmed cases, deaths, and recoveries. + """ + data = self.userrequestsetup.request("/v2/latest") + return data["latest"] + + + #get the latest changes (i.e.latest deltas) def getLatestChanges(self): changes = None if self.previousData: @@ -91,13 +125,8 @@ def getLatestChanges(self): } return changes - def getLatest(self) -> List[Dict[str, int]]: - """ - :return: The latest amount of total confirmed cases, deaths, and recoveries. - """ - data = self._request("/v2/latest") - return data["latest"] + #get case data relating all locations with COVID-19 def getLocations(self, timelines=False, rank_by: str = None) -> List[Dict]: """ Gets all locations affected by COVID-19, as well as latest case data. @@ -107,12 +136,11 @@ def getLocations(self, timelines=False, rank_by: str = None) -> List[Dict]: """ data = None if timelines: - data = self._request("/v2/locations", {"timelines": str(timelines).lower()}) + data = self.userrequestsetup.request("/v2/locations", {"timelines": str(timelines).lower()}) else: - data = self._request("/v2/locations") + data = self.userrequestsetup.request("/v2/locations") data = data["locations"] - ranking_criteria = ['confirmed', 'deaths', 'recovered'] if rank_by is not None: if rank_by not in ranking_criteria: @@ -120,39 +148,48 @@ def getLocations(self, timelines=False, rank_by: str = None) -> List[Dict]: ranked = sorted(data, key=lambda i: i['latest'][rank_by], reverse=True) data = ranked - return data - def getLocationByCountryCode(self, country_code, timelines=False) -> List[Dict]: + +############################### +# Country-based data searches +############################### + + #get case data by method of country name + def getLocationByCountry(self, country, timelines=False) -> List[Dict]: """ - :param country_code: String denoting the ISO 3166-1 alpha-2 code (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the country + :param country: String denoting name of the country :param timelines: Whether timeline information should be returned as well. - :return: A list of areas that correspond to the country_code. If the country_code is invalid, it returns an empty list. + :return: A list of areas that correspond to the country name. If the country is invalid, it returns an empty list. """ data = None if timelines: - data = self._request("/v2/locations", {"country_code": country_code, "timelines": str(timelines).lower()}) + data = self.userrequestsetup.request("/v2/locations", {"country": country, "timelines": str(timelines).lower()}) else: - data = self._request("/v2/locations", {"country_code": country_code}) + data = self.userrequestsetup.request("/v2/locations", {"country": country}) return data["locations"] - - def getLocationByCountry(self, country, timelines=False) -> List[Dict]: + + + #get case data by method of country code + def getLocationByCountryCode(self, country_code, timelines=False) -> List[Dict]: """ - :param country: String denoting name of the country + :param country_code: String denoting the ISO 3166-1 alpha-2 code (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) of the country :param timelines: Whether timeline information should be returned as well. - :return: A list of areas that correspond to the country name. If the country is invalid, it returns an empty list. + :return: A list of areas that correspond to the country_code. If the country_code is invalid, it returns an empty list. """ data = None if timelines: - data = self._request("/v2/locations", {"country": country, "timelines": str(timelines).lower()}) + data = self.userrequestsetup.request("/v2/locations", {"country_code": country_code, "timelines": str(timelines).lower()}) else: - data = self._request("/v2/locations", {"country": country}) + data = self.userrequestsetup.request("/v2/locations", {"country_code": country_code}) return data["locations"] + + #get case data by method of country id def getLocationById(self, country_id: int): """ :param country_id: Country Id, an int :return: A dictionary with case information for the specified location. """ - data = self._request("/v2/locations/" + str(country_id)) + data = self.userrequestsetup.request("/v2/locations/" + str(country_id)) return data["location"]