forked from ExpDev07/coronavirus-tracker-api
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlocation.py
More file actions
135 lines (105 loc) · 3.76 KB
/
location.py
File metadata and controls
135 lines (105 loc) · 3.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""app.location.py"""
import datetime as dt
import logging
from pprint import pformat as pf
from typing import Dict
import pydantic
from .models import Latest
from .utils import countries
from .utils.populations import country_population
LOGGER = logging.getLogger("app.location")
class Coordinates(pydantic.BaseModel):
"""
A position on earth using decimal coordinates (latitude and longitude).
"""
latitude: float = 0.0
longitude: float = 0.0
def __str__(self):
return f"lat: {self.latitude}, long: {self.longitude}"
class BaseLocation(pydantic.BaseModel):
"""A location in the world affected by the coronavirus."""
id: int
country: str
country_code: str = None
country_population: int = None
province: str = None
county: str = None
# coordinates
latitude: float = 0.0 # elide
longitude: float = 0.0 # elide
coordinates: Coordinates = None
# Last update.
last_updated: str = f"{dt.datetime.utcnow()}Z"
# Statistics
confirmed: int = 0 # elide
deaths: int = 0 # elide
recovered: int = 0 # elide
latest: Latest = None # Latest 'statistics'
class Config: # pylint: disable=too-few-public-methods
"""pydantic model settings."""
anystr_strip_whitespace = True
@pydantic.validator("latest", pre=True, always=True)
@classmethod
def set_latest(cls, v, values):
if v:
return v
return {
"confirmed": values["confirmed"],
"deaths": values["deaths"],
"recovered": values["recovered"],
}
@pydantic.validator("country_code", always=True)
@classmethod
def set_country_code(cls, v, values):
"""Gets the alpha-2 code represention of the country. Returns 'XX' if none is found."""
if v:
return v
return countries.country_code(values.get("country", countries.DEFAULT_COUNTRY_CODE)).upper()
@pydantic.validator("country_population", always=True)
@classmethod
def set_country_population(cls, v, values):
"""Gets the population of this location."""
if v:
return v
return country_population(values["country_code"])
@pydantic.validator("coordinates", always=True)
@classmethod
def set_coordinates(cls, v, values):
"""Sets the coordinates of the location."""
if v:
return v
return {"latitude": values["latitude"], "longitude": values["longitude"]}
def dict(self, *args, exclude=None, exclude_none=True, **kwargs):
elided_keys = {"confirmed", "deaths", "recovered", "latitude", "longitude"}
if exclude:
elided_keys.update(exclude)
return super().dict(*args, exclude=elided_keys, exclude_none=True, **kwargs)
class TimelinedLocation(BaseLocation):
"""
A location with timelines.
"""
timelines: Dict = {}
@pydantic.validator("timelines", always=True)
@classmethod
def serialize_timelines(cls, d):
return {k: v.serialize() for (k, v) in d.items()}
def dict(self, timelines=False, **kwargs) -> Dict:
"""Serializes the location into a dict."""
serialized = super().dict(**kwargs)
if timelines is False:
serialized.pop("timelines")
else:
# NOTE this does not actually set the value
serialized["latest"]["confirmed"] = serialized["timelines"]["confirmed"]["latest"]
# Return the serialized location.
return serialized
class USLocation(TimelinedLocation):
country: str = "US"
country_code: str = "US"
state: str
@pydantic.root_validator
@classmethod
def set_province(cls, values):
"""Sets the province according to the `state`."""
values["province"] = values["state"]
return values