Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ install:
- "pip install pipenv"
- "pipenv install --dev --skip-lock"
script:
- "make test lint"
- "make test lint check-fmt"
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@ test:

lint:
pylint $(APP) || true

fmt:
isort --apply --atomic
black . -l 120

check-fmt:
isort -rc --check
black . --check --diff
4 changes: 4 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ verify_ssl = true

[dev-packages]
bandit = "*"
black = "==19.10b0"
isort = "*"
pytest = "*"
pylint = "*"

Expand All @@ -25,3 +27,5 @@ python_version = "3.8"
[scripts]
dev = "uvicorn app.main:APP --reload"
start = "uvicorn app.main:APP"
fmt = "black . -l 120"
sort = "isort --apply --atomic"
91 changes: 90 additions & 1 deletion Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Support multiple data-sources.
[![GitHub last commit](https://img.shields.io/github/last-commit/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/commits/master)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/pulls)
[![GitHub issues](https://img.shields.io/github/issues/ExpDev07/coronavirus-tracker-api)](https://github.com/ExpDev07/coronavirus-tracker-api/issues)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Tweet](https://img.shields.io/twitter/url?url=https%3A%2F%2Fgithub.com%2FExpDev07%2Fcoronavirus-tracker-api)](https://twitter.com/intent/tweet?text=COVID19%20Live%20Tracking%20API:%20&url=https%3A%2F%2Fgithub.com%2FExpDev07%2Fcoronavirus-tracker-api)

**Live global stats (provided by [fight-covid19/bagdes](https://github.com/fight-covid19/bagdes)) from this API:**
Expand Down
2 changes: 1 addition & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# See PEP396.
__version__ = '2.0'
__version__ = "2.0"

from .core import create_app
3 changes: 2 additions & 1 deletion app/config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

# Load enviroment variables from .env file.
from dotenv import load_dotenv

load_dotenv()

"""
The port to serve the app application on.
"""
PORT = int(os.getenv('PORT', 5000))
PORT = int(os.getenv("PORT", 5000))
7 changes: 2 additions & 5 deletions app/coordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ def serialize(self):
:returns: The serialized coordinates.
:rtype: dict
"""
return {
'latitude' : self.latitude,
'longitude': self.longitude
}
return {"latitude": self.latitude, "longitude": self.longitude}

def __str__(self):
return 'lat: %s, long: %s' % (self.latitude, self.longitude)
return "lat: %s, long: %s" % (self.latitude, self.longitude)
3 changes: 2 additions & 1 deletion app/core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask import Flask
from flask_cors import CORS


def create_app():
"""
Construct the core application.
Expand All @@ -10,7 +11,7 @@ def create_app():
CORS(app)

# Set app config from settings.
app.config.from_pyfile('config/settings.py');
app.config.from_pyfile("config/settings.py")

with app.app_context():
# Import routes.
Expand Down
10 changes: 4 additions & 6 deletions app/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from ..services.location.jhu import JhuLocationService
from ..services.location.csbs import CSBSLocationService
from ..services.location.jhu import JhuLocationService

# Mapping of services to data-sources.
data_sources = {
'jhu': JhuLocationService(),
'csbs': CSBSLocationService()
}
data_sources = {"jhu": JhuLocationService(), "csbs": CSBSLocationService()}


def data_source(source):
"""
Expand All @@ -14,4 +12,4 @@ def data_source(source):
:returns: The service.
:rtype: LocationService
"""
return data_sources.get(source.lower())
return data_sources.get(source.lower())
6 changes: 4 additions & 2 deletions app/enums/sources.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from enum import Enum


class Sources(str, Enum):
"""
A source available for retrieving data.
"""
jhu = 'jhu'
csbs = 'csbs'

jhu = "jhu"
csbs = "csbs"
55 changes: 29 additions & 26 deletions app/location/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from ..utils import countrycodes
from ..utils.populations import country_population


class Location:
"""
A location in the world affected by the coronavirus.
Expand All @@ -21,7 +22,7 @@ def __init__(self, id, country, province, coordinates, last_updated, confirmed,
self.confirmed = confirmed
self.deaths = deaths
self.recovered = recovered

@property
def country_code(self):
"""
Expand Down Expand Up @@ -51,26 +52,20 @@ def serialize(self):
"""
return {
# General info.
'id' : self.id,
'country' : self.country,
'country_code' : self.country_code,
'country_population': self.country_population,
'province' : self.province,

"id": self.id,
"country": self.country,
"country_code": self.country_code,
"country_population": self.country_population,
"province": self.province,
# Coordinates.
'coordinates': self.coordinates.serialize(),

"coordinates": self.coordinates.serialize(),
# Last updated.
'last_updated': self.last_updated,

"last_updated": self.last_updated,
# Latest data (statistics).
'latest': {
'confirmed': self.confirmed,
'deaths' : self.deaths,
'recovered': self.recovered
},
"latest": {"confirmed": self.confirmed, "deaths": self.deaths, "recovered": self.recovered},
}


class TimelinedLocation(Location):
"""
A location with timelines.
Expand All @@ -79,18 +74,21 @@ class TimelinedLocation(Location):
def __init__(self, id, country, province, coordinates, last_updated, timelines):
super().__init__(
# General info.
id, country, province, coordinates, last_updated,

id,
country,
province,
coordinates,
last_updated,
# Statistics (retrieve latest from timelines).
confirmed=timelines.get('confirmed').latest or 0,
deaths=timelines.get('deaths').latest or 0,
recovered=timelines.get('recovered').latest or 0,
confirmed=timelines.get("confirmed").latest or 0,
deaths=timelines.get("deaths").latest or 0,
recovered=timelines.get("recovered").latest or 0,
)

# Set timelines.
self.timelines = timelines

def serialize(self, timelines = False):
def serialize(self, timelines=False):
"""
Serializes the location into a dict.

Expand All @@ -102,10 +100,15 @@ def serialize(self, timelines = False):

# Whether to include the timelines or not.
if timelines:
serialized.update({ 'timelines': {
# Serialize all the timelines.
key: value.serialize() for (key, value) in self.timelines.items()
}})
serialized.update(
{
"timelines": {
# Serialize all the timelines.
key: value.serialize()
for (key, value) in self.timelines.items()
}
}
)

# Return the serialized location.
return serialized
Loading