diff --git a/app/location/__init__.py b/app/location/__init__.py index 1da5e9e5..9e505631 100644 --- a/app/location/__init__.py +++ b/app/location/__init__.py @@ -3,9 +3,18 @@ from ..utils import countries from ..utils.populations import country_population +from abc import abstractmethod, ABCMeta + +class ILocation(metaclass=ABCMeta): + + @abstractmethod + def serialize(): + """ + Serializes the location into a dict. + """ # pylint: disable=redefined-builtin,invalid-name -class Location: # pylint: disable=too-many-instance-attributes +class Location(ILocation): # pylint: disable=too-many-instance-attributes """ A location in the world affected by the coronavirus. """ @@ -73,6 +82,81 @@ def serialize(self): }, } +# pylint: disable=redefined-builtin,invalid-name +class LocationAdapter(Location): # pylint: disable=too-many-instance-attributes + """ + A location in the world affected by the coronavirus. + """ + + def __init__( + self, id, country, province, coordinates, last_updated, confirmed, deaths, recovered, + ): # pylint: disable=too-many-arguments + # General info. + self.id = id + self.country = country.strip() + self.province = province.strip() + self.coordinates = coordinates + + # Last update. + self.last_updated = last_updated + + # Statistics. + self.confirmed = confirmed + self.deaths = deaths + self.recovered = recovered + + @property + def country_code(self): + """ + Gets the alpha-2 code represention of the country. Returns 'XX' if none is found. + + :returns: The country code. + :rtype: str + """ + return (countries.country_code(self.country) or countries.DEFAULT_COUNTRY_CODE).upper() + + @property + def country_population(self): + """ + Gets the population of this location. + + :returns: The population. + :rtype: int + """ + return country_population(self.country_code) + + def serialize(self): + """ + Serializes the location into a dict. + + :returns: The serialized location. + :rtype: dict + """ + serialized = { + # General info. + "id": self.id, + "country": self.country, + "country_code": self.country_code, + "country_population": self.country_population, + "province": self.province, + # Coordinates. + "coordinates": self.coordinates.serialize(), + # Last updated. + "last_updated": self.last_updated, + # Latest data (statistics). + "latest": { + "confirmed": self.confirmed, + "deaths": self.deaths, + "recovered": self.recovered, + }, + } + + # Update with new fields. + serialized.update( + {"state": self.province, "county": self.county,} + ) + + return serialized class TimelinedLocation(Location): """ diff --git a/app/location/csbs.py b/app/location/csbs.py index 649e8b22..d73dfe12 100644 --- a/app/location/csbs.py +++ b/app/location/csbs.py @@ -1,8 +1,8 @@ """app.locations.csbs.py""" -from . import Location +from . import LocationAdapter -class CSBSLocation(Location): +class CSBSLocation(LocationAdapter): """ A CSBS (county) location. """ @@ -34,10 +34,5 @@ def serialize(self, timelines=False): # pylint: disable=arguments-differ,unused """ serialized = super().serialize() - # Update with new fields. - serialized.update( - {"state": self.state, "county": self.county,} - ) - # Return the serialized location. return serialized diff --git a/app/utils/baseurls.py b/app/utils/baseurls.py new file mode 100644 index 00000000..ccebf743 --- /dev/null +++ b/app/utils/baseurls.py @@ -0,0 +1,10 @@ +import enum + +class BaseUrl(str, enum.Enum): + """ + A base url available for retrieving data. + """ + + JHU = "https://raw.githubusercontent.com/CSSEGISandData/2019-nCoV/master/csse_covid_19_data/csse_covid_19_time_series/" + CSBS = "https://facts.csbs.org/covid-19/covid19_county.csv" + NYT = "https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-counties.csv"