Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@
]
SOURCES = [
"https://github.com/CSSEGISandData/COVID-19",
"https://github.com/govex/COVID-19",
"https://www.worldometers.info/coronavirus/"
]
route_homepage = {
"documentation": f"{BASE_PATH}/doc",
"routes": ROUTES,
"<data_type>": "confirmed | recovered | deaths",
"<data_type>": "confirmed | recovered | deaths | vaccinated",
"Api version": API_VERSION,
"discord": "https://discord.gg/wTxbQYb",
"sources": SOURCES,
Expand All @@ -52,6 +53,8 @@

app = Flask(__name__)
app.url_map.strict_slashes = False
# Flask orders the dates wrong for some reason ?!?!
app.config['JSON_SORT_KEYS'] = False
limiter = Limiter(
app,
get_remote_address,
Expand Down Expand Up @@ -431,96 +434,96 @@ def get(self, data_type: int):
@api.route(f"/api/{API_VERSION}/history/<data_type>/<country>/")
class HistoryDataTypeCountry(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`", "country": "Full name or ISO-3166-1"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`", "country": "Full name or ISO-3166-1"})
def get(self, data_type: str, country: str):
return history_country(data_type, country)


@api.route(f"/api/{API_VERSION}/history/<data_type>/<country>/<region>")
class HistoryDataTypeRegion(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`", "country": "Full name or ISO-3166-1", "region": "Region name"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`", "country": "Full name or ISO-3166-1", "region": "Region name"})
def get(self, data_type: str, country: str, region: str):
return history_region(data_type, country, region)


@api.route(f"/api/{API_VERSION}/history/<data_type>/<country>/regions")
class HistoryDataTypeRegions(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`", "country": "Full name or ISO-3166-1"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`", "country": "Full name or ISO-3166-1"})
def get(self, data_type: str, country: str):
return history_region_all(data_type, country)


@api.route(f"/api/{API_VERSION}/history/<data_type>/total")
class HistoryDataTypeTotal(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"})
def get(self, data_type: str):
return history_region_world(data_type)


@api.route(f"/api/{API_VERSION}/proportion/<data_type>/")
class ProportionDataType(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"})
def get(self, data_type: str):
return proportion(data_type)

@api.route(f"/api/{API_VERSION}/proportion/<data_type>/total")
class ProportionDataTypeTotal(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"},
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"},
description="Returns the percentage of the world's population to be affected by COVID-19")
def get(self, data_type: str):
return proportion_region_world(data_type)

@api.route(f"/api/{API_VERSION}/proportion/<data_type>/<country>/")
class ProportionDataTypeCountry(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`", "country": "Full name or ISO-3166-1"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`", "country": "Full name or ISO-3166-1"})
def get(self, data_type: str, country: str):
return proportion_country(data_type, country)

@api.route(f"/api/{API_VERSION}/daily/<data_type>/")
class DailyDataType(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"})
def get(self, data_type: str):
return daily(data_type)

@api.route(f"/api/{API_VERSION}/daily/<data_type>/total")
class DailyDataTypeTotal(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"})
def get(self, data_type: str):
return daily_region_world(data_type)

@api.route(f"/api/{API_VERSION}/daily/<data_type>/<country>/")
class DailyDataTypeCountry(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`", "country": "Full name or ISO-3166-1"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`", "country": "Full name or ISO-3166-1"})
def get(self, data_type: str, country: str):
return daily_country(data_type, country)

@api.route(f"/api/{API_VERSION}/proportion-daily/<data_type>/")
class ProportionDailyDataType(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"})
def get(self, data_type: str):
return proportion_daily(data_type)

@api.route(f"/api/{API_VERSION}/proportion-daily/<data_type>/total")
class ProportionDailyDataTypeTotal(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`"})
def get(self, data_type: str):
return proportion_daily_region_world(data_type)

@api.route(f"/api/{API_VERSION}/proportion-daily/<data_type>/<country>")
class ProportionDailyDataTypeCountry(Resource):
@api.doc(responses=responses,
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths`", "country": "Full name or ISO-3166-1"})
params={"data_type": "Input accepted : `confirmed` | `recovered` | `deaths` | `vaccinated`", "country": "Full name or ISO-3166-1"})
def get(self, data_type: str, country: str):
return proportion_daily_country(data_type, country)

Expand Down
79 changes: 60 additions & 19 deletions src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
CSV_CONFIRMED = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv"
CSV_DEATHS = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv"
CSV_RECOVERED = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv"
CSV_VACCINATED = "https://raw.githubusercontent.com/govex/COVID-19/master/data_tables/vaccine_data/global_data/time_series_covid19_vaccine_doses_admin_global.csv"

CSV_CONFIRMED_US = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_US.csv"
CSV_DEATHS_US = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_US.csv"
Expand All @@ -27,6 +28,7 @@
CSV_CONFIRMED_FPATH = "csv_confirmed.csv"
CSV_DEATHS_FPATH = "csv_deaths.csv"
CSV_RECOVERD_FPATH = "csv_recovered.csv"
CSV_VACCINATED_FPATH = "csv_vaccinated.csv"

CSV_POPULATIONS = "data/populations.csv"
populations = {}
Expand Down Expand Up @@ -70,14 +72,17 @@ def update():
dl_csv(CSV_CONFIRMED, CSV_CONFIRMED_FPATH)
dl_csv(CSV_DEATHS, CSV_DEATHS_FPATH)
dl_csv(CSV_RECOVERED, CSV_RECOVERD_FPATH)
dl_csv(CSV_VACCINATED, CSV_VACCINATED_FPATH)
dl_csv(CSV_CONFIRMED_US, CSV_CONFIRMED_FPATH_US)
dl_csv(CSV_DEATHS_US, CSV_DEATHS_FPATH_US)
csv_to_json(CSV_CONFIRMED_FPATH)
csv_to_json(CSV_DEATHS_FPATH)
csv_to_json(CSV_RECOVERD_FPATH)
csv_to_json(CSV_VACCINATED_FPATH, is_govex=True)
region_csv_to_json(CSV_CONFIRMED_FPATH)
region_csv_to_json(CSV_DEATHS_FPATH)
region_csv_to_json(CSV_RECOVERD_FPATH)
region_csv_to_json(CSV_VACCINATED_FPATH, is_govex=True)
region_csv_to_json(CSV_CONFIRMED_FPATH_US, is_us=True)
region_csv_to_json(CSV_DEATHS_FPATH_US, is_us=True)
store_data()
Expand All @@ -87,26 +92,42 @@ def dl_csv(csv_type, fpath):
with open(fpath, "w+") as f:
f.write(r.text)

def csv_to_json(csv_fpath):
def csv_to_json(csv_fpath, is_govex=False):
csv_json = {}

if is_govex:
province_key = "Province_State"
country_key = "Country_Region"
key_start = 12
date_format = "%Y-%m-%d"
else:
province_key = "Province/State"
country_key = "Country/Region"
key_start = 4
date_format = "%m/%d/%y"

with open("iso-3166.json", "r") as isof:
iso_data = json.load(isof)
with open(csv_fpath, "r") as csv_file:
data = csv.DictReader(csv_file)
for row in data:
if row["Country/Region"] not in csv_json:
if row["Country/Region"] in SPECIAL_CASES:
country = SPECIAL_CASES[row["Country/Region"]]["name"]
if row[country_key] not in csv_json:
if row[country_key] in SPECIAL_CASES:
country = SPECIAL_CASES[row[country_key]]["name"]
else:
country = row["Country/Region"]
country = row[country_key]
csv_json[country] = {"history": {}}
for key in list(row.keys())[4:]:
new_k = datetime.datetime.strptime(key, "%m/%d/%y").strftime("%m/%d/%y")
csv_json[country]["history"][new_k] = int(row[key])
else:
for key in list(row.keys())[4:]:
new_k = datetime.datetime.strptime(key, "%m/%d/%y").strftime("%m/%d/%y")
csv_json[country]["history"][new_k] += int(row[key])
for key in list(row.keys())[key_start:]:
new_k = datetime.datetime.strptime(key, date_format).strftime("%m/%d/%y")
csv_json[country]["history"][new_k] = int(row[key]) if (row[key] != '') else 0
elif is_govex != True:
for key in list(row.keys())[key_start:]:
new_k = datetime.datetime.strptime(key, date_format).strftime("%m/%d/%y")
csv_json[country]["history"][new_k] += int(row[key]) if (row[key] != '') else 0

#print(csv_json[country]["history"])
#csv_json[country]["history"] = dict(sorted(csv_json[country]["history"].items(), key=lambda p: p[1]))
#print(csv_json[country]["history"])

for k in csv_json.keys():
for iso in iso_data:
Expand All @@ -124,16 +145,30 @@ def csv_to_json(csv_fpath):
with open(csv_fpath.replace(".csv", ".json"), "w+") as f:
f.write(str(json.dumps(csv_json)))

def region_csv_to_json(csv_fpath, is_us=False):
def region_csv_to_json(csv_fpath, is_us=False, is_govex=False):
csv_json = {}
if is_us:
province_key = "Province_State"
country_key = "Country_Region"
key_start = 12
date_format = "%m/%d/%y"
else:
province_key = "Province/State"
country_key = "Country/Region"
key_start = 4
date_format = "%m/%d/%y"

if is_govex:
province_key = "Province_State"
country_key = "Country_Region"
key_start = 12
date_format = "%Y-%m-%d"
elif is_us == False:
province_key = "Province/State"
country_key = "Country/Region"
key_start = 4
date_format = "%m/%d/%y"

with open("iso-3166.json", "r") as isof:
iso_data = json.load(isof)
with open(csv_fpath, "r") as csv_file:
Expand All @@ -150,24 +185,24 @@ def region_csv_to_json(csv_fpath, is_us=False):
csv_json[country] = {"regions": {}}
province = row[province_key]
for key in list(row.keys())[key_start:]:
new_k = datetime.datetime.strptime(key, "%m/%d/%y").strftime("%m/%d/%y")
new_k = datetime.datetime.strptime(key, date_format).strftime("%m/%d/%y")
if province not in csv_json[country]["regions"]:
csv_json[country]["regions"][province] = {
"history": {}
}
csv_json[country]["regions"][province]["history"][new_k] = int(float(row[key]))
else:
csv_json[country]["regions"][province]["history"][new_k] = int(float(row[key])) if (row[key] != '') else 0
elif is_govex != True:
province = row[province_key]
for key in list(row.keys())[key_start:]:
new_k = datetime.datetime.strptime(key, "%m/%d/%y").strftime("%m/%d/%y")
new_k = datetime.datetime.strptime(key, date_format).strftime("%m/%d/%y")
if province not in csv_json[country]["regions"]:
csv_json[country]["regions"][province] = {
"history": {}
}
if is_us and csv_json[country]["regions"][province]["history"].get(new_k):
csv_json[country]["regions"][province]["history"][new_k] += int(float(row[key]))
csv_json[country]["regions"][province]["history"][new_k] += int(float(row[key])) if (row[key] != '') else 0
else:
csv_json[country]["regions"][province]["history"][new_k] = int(float(row[key]))
csv_json[country]["regions"][province]["history"][new_k] = int(float(row[key])) if (row[key] != '') else 0


for k in csv_json.keys():
Expand Down Expand Up @@ -208,11 +243,16 @@ def replace_null_value(dataset: list):
data_c = read_json(CSV_CONFIRMED_FPATH.replace(".csv", ".json"))
data_r = read_json(CSV_RECOVERD_FPATH.replace(".csv", ".json"))
data_d = read_json(CSV_DEATHS_FPATH.replace(".csv", ".json"))
data_v = read_json(CSV_VACCINATED_FPATH.replace(".csv", ".json"))
for kv_replace in dataset:
tmp = kv_replace
confirmed = find_val_replace_null(tmp["country"], data_c, tmp["totalCases"])
recovered = find_val_replace_null(tmp["country"], data_r, tmp["totalRecovered"])
deaths = find_val_replace_null(tmp["country"], data_d, tmp["totalDeaths"])
# TODO: find / calculate data for whole world vaccinations
if tmp["country"] in data_v:
tmp["totalVaccinated"] = list(data_v[tmp["country"]]["history"].values())[-1]

if tmp["totalCases"] is None:
tmp["totalCases"] = confirmed
if tmp["activeCases"] is None:
Expand All @@ -223,6 +263,7 @@ def replace_null_value(dataset: list):
tmp["totalDeaths"] = deaths
if tmp["totalRecovered"] is None:
tmp["totalRecovered"] = recovered

new_dataset.append(tmp)
return new_dataset

Expand Down