From 308fbc05e6fc6cb0b19e61b86287affbda01a213 Mon Sep 17 00:00:00 2001 From: Fabrizio Miano Date: Sun, 21 Feb 2021 20:11:15 +0100 Subject: [PATCH] =?UTF-8?q?v4.4.0:=20=F0=9F=92=BC=20Use=20celery=20for=20c?= =?UTF-8?q?ollection-update=20long=20background=20job=20(#11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix collections update request timeout: use Celery! * Refactor: rename config.py to constants.py * Update .env.example * Update .dockerignore * Update requirements.txt --- .dockerignore | 21 +- .env.example | 8 +- Procfile | 3 +- app/__init__.py | 50 +-- app/api/endpoints.py | 228 ++++++------- app/data/__init__.py | 4 +- app/data/etl.py | 2 +- app/db/create.py | 26 +- app/db/{update.py => tasks.py} | 43 ++- app/plotter/__init__.py | 2 +- app/ui/pandemic.py | 2 +- app/ui/vaccines.py | 2 +- app/utils/__init__.py | 2 +- celery_worker.py | 14 + config.py | 603 ++------------------------------- constants.py | 593 ++++++++++++++++++++++++++++++++ requirements.txt | 2 + 17 files changed, 842 insertions(+), 763 deletions(-) rename app/db/{update.py => tasks.py} (93%) create mode 100644 celery_worker.py create mode 100644 constants.py diff --git a/.dockerignore b/.dockerignore index e34fa73..51f2002 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,12 +1,31 @@ +# python compiled +*.pyc +__pycache__/ + +# ide stuff +.idea +.vscode + +# node modules +node_modules/ + # images *.png -# py notebooks +# notebooks *.ipynb # git / github stuff +.git/ .github/ *.gitignore +*.md +LICENSE +docs/ +previews/ # misc *.log +*.json +*.bat +*.sh diff --git a/.env.example b/.env.example index 561bfd5..347629a 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,18 @@ +APPLICATION_ENV=production MONGO_URI=changeme NATIONAL_DATA_COLLECTION=changeme -REGIONAL_DATA_COLLECTION=changeme -PROVINCIAL_DATA_COLLECTION=changeme NATIONAL_TRENDS_COLLECTION=changeme NATIONAL_SERIES_COLLECTION=changeme +REGIONAL_DATA_COLLECTION=changeme REGIONAL_TRENDS_COLLECTION=changeme REGIONAL_SERIES_COLLECTION=changeme REGIONAL_BREAKDOWN_COLLECTION=changeme +PROVINCIAL_DATA_COLLECTION=changeme PROVINCIAL_BREAKDOWN_COLLECTION=changeme PROVINCIAL_TRENDS_COLLECTION=changeme PROVINCIAL_SERIES_COLLECTION=changeme VAX_COLLECTION=changeme VAX_SUMMARY_COLLECTION=changeme GH_WEBHOOK_SECRET=changeme -SECRET_KEY=changeme +API_KEY=changeme +REDIS_URL=changeme \ No newline at end of file diff --git a/Procfile b/Procfile index abab492..b62505d 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,3 @@ release: python -m flask create-collections -web: gunicorn wsgi:app \ No newline at end of file +web: gunicorn wsgi:app +worker: celery -A celery_worker.celery worker \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py index 88c2ee3..ac70600 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,6 +4,7 @@ import os import click +from celery import Celery from dotenv import load_dotenv from flask import Flask, request, render_template, send_from_directory from flask_babel import Babel @@ -11,13 +12,15 @@ from flask_pymongo import PyMongo from flask_sitemap import Sitemap -from config import LANGUAGES, TRANSLATION_DIRNAME +from config import config as app_config +from constants import LANGUAGES, TRANSLATION_DIRNAME load_dotenv() mongo = PyMongo() babel = Babel() sitemap = Sitemap() compress = Compress() +celery = Celery(__name__) @babel.localeselector @@ -62,14 +65,18 @@ def favicon(): "favicon.ico", mimetype="image/vnd.microsoft.icon") +def get_environment(): + """Return app environment""" + return os.environ.get('APPLICATION_ENV') or 'development' + + def create_app(): """Create the flask application""" + env = get_environment() app = Flask(__name__) - translation_dir = os.path.join(app.root_path, TRANSLATION_DIRNAME) - app.config["BABEL_TRANSLATION_DIRECTORIES"] = translation_dir - app.config["SECRET_KEY"] = os.environ["SECRET_KEY"] - app.config["MONGO_URI"] = os.environ["MONGO_URI"] - app.config["SITEMAP_INCLUDE_RULES_WITHOUT_PARAMS"] = True + app.config.from_object(app_config[env]) + app.config["BABEL_TRANSLATION_DIRECTORIES"] = os.path.join( + app.root_path, TRANSLATION_DIRNAME) compress.init_app(app) mongo.init_app(app) babel.init_app(app) @@ -77,18 +84,11 @@ def create_app(): set_error_handlers(app) set_robots_txt_rule(app) set_favicon_rule(app) - - @app.after_request - def add_header(r): - """ - Add headers to both force latest IE rendering engine or Chrome Frame, - and also to cache the rendered page for 10 minutes. - """ - r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" - r.headers["Pragma"] = "no-cache" - r.headers["Expires"] = "0" - r.headers["Cache-Control"] = "public, max-age=0" - return r + celery.config_from_object(app.config) + celery.conf.update( + broker_url=app.config['BROKER_URL'], + result_backend=app.config['RESULT_BACKEND'] + ) from .ui import pandemic, vaccines app.register_blueprint(pandemic) @@ -125,6 +125,18 @@ def add_header(r): "vax_summary": create_vax_summary_collection } + @app.after_request + def add_header(r): + """ + Add headers to both force latest IE rendering engine or Chrome Frame, + and also to cache the rendered page for 10 minutes. + """ + r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" + r.headers["Pragma"] = "no-cache" + r.headers["Expires"] = "0" + r.headers["Cache-Control"] = "public, max-age=0" + return r + @app.cli.command("create-collections") def populate_db(): """Populate all the collections needed on mongoDB""" @@ -135,7 +147,7 @@ def populate_db(): @click.argument("collection_type") def populate_collection(collection_type): """ - Populate a collection_type ob mongoDB. + Populate a collection_type on mongoDB. Choose one of the following: "national", "regional", "provincial", "latest_regional", "latest_provincial", "national_trends", "regional_trends", diff --git a/app/api/endpoints.py b/app/api/endpoints.py index 01d0337..984cef7 100644 --- a/app/api/endpoints.py +++ b/app/api/endpoints.py @@ -5,7 +5,7 @@ from flask_github_signature import verify_signature from app.api import api -from app.db.update import ( +from app.db.tasks import ( update_national_collection, update_national_series_collection, update_national_trends_collection, update_regional_collection, update_regional_series_collection, update_regional_trends_collection, @@ -16,18 +16,18 @@ from app.plotter import Plotter, validate_plot_request -@api.route("/plot") +@api.route('/plot') def plot_trend(): """ API to make plot for a given data_type, varname, and area - "varname" must always be specified, together with "data_type". - If "data_type" is "national" no "area" is needed. - As opposite, if "data_type" is "regional" or "provincial" an "area" + 'varname' must always be specified, together with 'data_type'. + If 'data_type' is 'national' no 'area' is needed. + As opposite, if 'data_type' is 'regional' or 'provincial' an 'area' must be specified. - The specified "varname" must be one of the VARS keys for "national" and - "regional" data types, and can only be "totale_casi" or - "nuovi_positivi" for the "provincial" data type + The specified 'varname' must be one of the VARS keys for 'national' and + 'regional' data types, and can only be 'totale_casi' or + 'nuovi_positivi' for the 'provincial' data type Example 1: GET /plot/varname=nuovi_positivi&data_type=provincial&area=Catania @@ -39,141 +39,121 @@ def plot_trend(): if 'download' in query string flask.Response object else JSON str, e.g. { - "status": "ok", - "errors": [], - "img": "some_b64" + 'status': 'ok', + 'errors': [], + 'img': 'some_b64' } """ - response = {"status": "ko", "errors": []} + response = {'status': 'ko', 'errors': []} status = 400 - varname = request.args.get("varname") - data_type = request.args.get("data_type") - area = request.args.get("area") - download = request.args.get("download") + varname = request.args.get('varname') + data_type = request.args.get('data_type') + area = request.args.get('area') + download = request.args.get('download') is_valid, err = validate_plot_request(varname, data_type, area) if is_valid: try: p = Plotter(varname, data_type, area=area) if download: img_bytes = p.to_bytes() - response = Response(img_bytes, mimetype="image/png") + response = Response(img_bytes, mimetype='image/png') else: img = p.to_b64() - response["img"] = img - response["status"] = "ok" + response['img'] = img + response['status'] = 'ok' response = jsonify(**response) status = 200 except Exception as e: - app.logger.error(f"{e}") - response["errors"].extend([f"{e}"]) + app.logger.error(f'{e}') + response['errors'].extend([f'{e}']) status = 400 else: - response["errors"].append(err) + response['errors'].append(err) return response, status -@api.route("/update/national", methods=["POST"]) -@verify_signature -def trigger_national_coll_update(): - """Trigger national collection update""" - app.logger.warning("Triggered national data update") - response = update_national_collection() - return jsonify(**response) - - -@api.route("/update/national/series", methods=["POST"]) -@verify_signature -def trigger_national_series_collection_update(): - """Trigger national series collection update""" - app.logger.warning("Triggered national series update") - response = update_national_series_collection() - return jsonify(**response) - - -@api.route("/update/national/trends", methods=["POST"]) -@verify_signature -def trigger_national_trends_collection_update(): - """Trigger national trends collection update""" - app.logger.warning("Triggered national trends update") - response = update_national_trends_collection() - return jsonify(**response) - - -@api.route("/update/regional", methods=["POST"]) -@verify_signature -def trigger_regional_collection_update(): - """Trigger regional-data collection update""" - app.logger.warning("Triggered regional data update") - response = update_regional_collection() - return jsonify(**response) - - -@api.route("/update/regional/series", methods=["POST"]) -@verify_signature -def trigger_regional_series_collection_update(): - """Trigger regional series collection update""" - app.logger.warning("Triggered regional series update") - response = update_regional_series_collection() - return jsonify(**response) - - -@api.route("update/regional/trends", methods=["POST"]) -def trigger_regional_trends_collection_update(): - """Trigger regional trends collection update""" - app.logger.warning("Triggered regional trends update") - response = update_regional_trends_collection() - return jsonify(**response) - - -@api.route("update/regional/breakdown", methods=["POST"]) -@verify_signature -def trigger_regional_breakdown_collection_update(): - """Trigger regional breakdown collection update""" - app.logger.warning("Triggered regional breakdown update") - response = update_regional_breakdown_collection() - return jsonify(**response) - - -@api.route("update/provincial", methods=["POST"]) -@verify_signature -def trigger_provincial_collection_update(): - """Trigger provincial data collection update""" - app.logger.warning("Triggered provincial data update") - response = update_provincial_collection() - return jsonify(**response) - - -@api.route("/update/provincial/breakdown", methods=["POST"]) -@verify_signature -def trigger_provincial_breakdown_collection_update(): - """Trigger provincial breakdown collection update""" - app.logger.warning("Triggered provincial breakdown update") - response = update_provincial_breakdown_collection() - return jsonify(**response) - - -@api.route("/update/provincial/", methods=["POST"]) -@verify_signature -def trigger_provincial_series_or_trends_collection_update(coll_type): - """Trigger provincial series OR trends collections update""" - app.logger.warning(f"Triggered provincial {coll_type} update") - response = update_provincial_series_or_trends_collection(coll_type) - return jsonify(**response) - - -@api.route("/update/vax", methods=["POST"]) -@verify_signature -def trigger_vax_collection_update(): - """Trigger vax or vax summary collection update""" - app.logger.warning(f"Triggered vax collection update") - response = update_vax_collection() - return jsonify(**response) +update_menu = { + 'national': { + 'root': { + 'task': update_national_collection, + 'args': None + }, + 'series': { + 'task': update_national_series_collection, + 'args': None + }, + 'trends': { + 'task': update_national_trends_collection, + 'args': None + } + }, + 'regional': { + 'root': { + 'task': update_regional_collection, + 'args': None + }, + 'breakdown': { + 'task': update_regional_breakdown_collection, + 'args': None + }, + 'series': { + 'task': update_regional_series_collection, + 'args': None + }, + 'trends': { + 'task': update_regional_trends_collection, + 'args': None + } + }, + 'provincial': { + 'root': { + 'task': update_provincial_collection, + 'args': None + }, + 'breakdown': { + 'task': update_provincial_breakdown_collection, + 'args': None + }, + 'series': { + 'task': update_provincial_series_or_trends_collection, + 'args': 'series' + }, + 'trends': { + 'task': update_provincial_series_or_trends_collection, + 'args': 'trends' + } + }, + 'vax': { + 'root': { + 'task': update_vax_collection, + 'args': None + }, + 'summary': { + 'task': update_vax_collection, + 'args': True + } + } +} -@api.route("/update/vax/summary", methods=["POST"]) +@api.route('/update/', methods=['POST']) +@api.route('/update//', methods=['POST']) @verify_signature -def trigger_vax_summary_collection_update(): - """Trigger vax or vax summary collection update""" - app.logger.warning(f"Triggered vax summary collection update") - response = update_vax_collection(summary=True) - return jsonify(**response) +def update_collection(data_type, coll_type='root'): + """Trigger collection update task""" + app.logger.warning(f'Triggered {data_type} {coll_type} data update') + status = 'ko' + try: + task_to_exec = update_menu[data_type][coll_type]['task'] + args = update_menu[data_type][coll_type]['args'] + if args: + task = task_to_exec.apply_async(args=[args]) + else: + task = task_to_exec.delay() + msg = f'Task {task.id} submitted. Status {task.state}' + app.logger.warning(msg) + status = 'ok' + except Exception as e: + msg = f'While submitting {data_type} {coll_type} update task: {e}' + app.logger.error(msg) + return jsonify(**{'status': status, 'msg': msg}) diff --git a/app/data/__init__.py b/app/data/__init__.py index 56160d5..d68c54c 100644 --- a/app/data/__init__.py +++ b/app/data/__init__.py @@ -16,7 +16,7 @@ VAX_SUMMARY_COLL ) from app.utils import rubbish_notes, translate_series_lang -from config import ( +from constants import ( REGION_KEY, PROVINCE_KEY, DATE_KEY, NOTE_KEY, DAILY_POSITIVITY_INDEX, UPDATE_FMT, VARS, ITALY_MAP, VERSION, REGIONS, PROVINCES, TOTAL_CASES_KEY, NEW_POSITIVE_KEY, KEY_PERIODS, URL_VAX_LATEST_UPDATE, @@ -260,7 +260,7 @@ def get_perc_pop_vax(tot_admins, population): def enrich_frontend_data(area=None, **data): """ Return a data dict to be rendered which is an augmented copy of - DASHBOARD_DATA defined in config.py + DASHBOARD_DATA defined in constants.py :param area: optional, str :param data: **kwargs :return: dict diff --git a/app/data/etl.py b/app/data/etl.py index cca6eef..5f1b943 100644 --- a/app/data/etl.py +++ b/app/data/etl.py @@ -8,7 +8,7 @@ CUM_QUANTITIES, NON_CUM_QUANTITIES, DAILY_QUANTITIES, TREND_CARDS, PROV_TREND_CARDS ) -from config import ( +from constants import ( VARS, DAILY_POSITIVITY_INDEX, NEW_POSITIVE_KEY, DAILY_SWABS_KEY, REGION_CODE, PROVINCE_CODE, TOTAL_CASES_KEY, REGION_KEY, PROVINCE_KEY, REGIONS, PROVINCES, DATE_KEY, CHART_DATE_FMT, STATE_KEY, diff --git a/app/db/create.py b/app/db/create.py index 2fb87f0..053bf3c 100644 --- a/app/db/create.py +++ b/app/db/create.py @@ -17,7 +17,7 @@ PROV_TRENDS_COLL, PROV_SERIES_COLL, PROV_BREAKDOWN_COLL, VAX_COLL, VAX_SUMMARY_COLL ) -from config import ( +from constants import ( URL_NATIONAL, URL_REGIONAL, URL_PROVINCIAL, DATE_KEY, URL_VAX_DATA, URL_VAX_ADMINS_SUMMARY_DATA, VAX_DATE_KEY ) @@ -31,7 +31,7 @@ def create_national_collection(): df_national_augmented = augment_national_df(df) national_records = df_national_augmented.to_dict(orient='records') try: - app.logger.warning("Doing national") + app.logger.warning("Doing National collection") NAT_DATA_COLL.drop() NAT_DATA_COLL.insert_many(national_records, ordered=True) response["collections_created"].append("national") @@ -52,7 +52,7 @@ def create_national_trends_collection(): df_national_augmented = augment_national_df(df) national_trends = build_national_trends(df_national_augmented) try: - app.logger.warning("Doing national_trends") + app.logger.warning("Doing national trends collection") NAT_TRENDS_COLL.drop() NAT_TRENDS_COLL.insert_many(national_trends) response["collections_created"].append("national_trends") @@ -73,7 +73,7 @@ def create_national_series_collection(): df_national_augmented = augment_national_df(df) national_series = build_national_series(df_national_augmented) try: - app.logger.warning("Doing national_series") + app.logger.warning("Doing national series collection") NAT_SERIES_COLL.drop() NAT_SERIES_COLL.insert_one(national_series) response["collections_created"].append("national_series") @@ -95,7 +95,7 @@ def create_regional_collection(): df_regional_augmented = augment_regional_df(df) regional_records = df_regional_augmented.to_dict(orient='records') try: - app.logger.warning("Doing regional") + app.logger.warning("Doing regional collection") REG_DATA_COLL.drop() REG_DATA_COLL.insert_many(regional_records, ordered=True) response["collections_created"].append("regional") @@ -116,7 +116,7 @@ def create_regional_breakdown_collection(): df_regional_augmented = augment_regional_df(df) regional_breakdown = build_regional_breakdown(df_regional_augmented) try: - app.logger.warning("Doing regional_breakdown") + app.logger.warning("Doing regional breakdown collection") REG_BREAKDOWN_COLL.drop() REG_BREAKDOWN_COLL.insert_one(regional_breakdown) response["collections_created"].append("regional_breakdown") @@ -137,7 +137,7 @@ def create_regional_series_collection(): df_regional_augmented = augment_regional_df(df) regional_series = build_regional_series(df_regional_augmented) try: - app.logger.warning("Doing regional_series") + app.logger.warning("Doing regional series collection") REG_SERIES_COLL.drop() REG_SERIES_COLL.insert_many(regional_series) response["collections_created"].append("regional_series") @@ -157,7 +157,7 @@ def create_regional_trends_collection(): df_regional_augmented = augment_regional_df(df) regional_trends = build_regional_trends(df_regional_augmented) try: - app.logger.warning("Doing regional_trends") + app.logger.warning("Doing regional trends collection") REG_TRENDS_COLL.drop() REG_TRENDS_COLL.insert_many(regional_trends) response["collections_created"].append("regional_trends") @@ -200,7 +200,7 @@ def create_provincial_breakdown_collection(): provincial_breakdowns = build_provincial_breakdowns( df_provincial_augmented) try: - app.logger.warning("Doing provincial_breakdowns") + app.logger.warning("Doing provincial breakdowns collection") PROV_BREAKDOWN_COLL.drop() PROV_BREAKDOWN_COLL.insert_many(provincial_breakdowns) response["collections_created"].append("provincial_breakdowns") @@ -222,7 +222,7 @@ def create_provincial_series_collection(): provincial_series = build_provincial_series( df_provincial_augmented) try: - app.logger.warning("Doing provincial_series") + app.logger.warning("Doing provincial series collection") PROV_SERIES_COLL.drop() PROV_SERIES_COLL.insert_many(provincial_series) response["collections_created"].append("provincial_series") @@ -243,7 +243,7 @@ def create_provincial_trends_collection(): df_provincial_augmented = augment_provincial_df(df) provincial_trends = build_provincial_trends(df_provincial_augmented) try: - app.logger.warning("Doing provincial_trends") + app.logger.warning("Doing provincial trends collection") PROV_TRENDS_COLL.drop() PROV_TRENDS_COLL.insert_many(provincial_trends) response["collections_created"].append("provincial_trends") @@ -259,7 +259,7 @@ def create_vax_collection(): """Create vaccine-data colleciton""" status = 500 response = {"status": "ko", "collections_created": [], "errors": []} - info_msg = "Doing Vax Collection" + info_msg = "Doing vax collection" err_msg = "While creating vax collection:" df = pd.read_csv(URL_VAX_DATA, parse_dates=[VAX_DATE_KEY]) df = augment_vax_df(df) @@ -281,7 +281,7 @@ def create_vax_summary_collection(): """Create vax summary collection""" status = 500 response = {"status": "ko", "collections_created": [], "errors": []} - info_msg = "Doing Vax Summary Collection" + info_msg = "Doing vax summary collection" err_msg = "While creating vax summary collection:" df = pd.read_csv(URL_VAX_ADMINS_SUMMARY_DATA, parse_dates=[VAX_DATE_KEY]) df = augment_summary_vax_df(df) diff --git a/app/db/update.py b/app/db/tasks.py similarity index 93% rename from app/db/update.py rename to app/db/tasks.py index a6636ae..5bd8943 100644 --- a/app/db/update.py +++ b/app/db/tasks.py @@ -1,30 +1,27 @@ """ -DB Update +Celery tasks """ import pandas as pd from flask import current_app as app from pymongo import UpdateOne, InsertOne -from app.data import ( - NAT_DATA_COLL, NAT_TRENDS_COLL, NAT_SERIES_COLL, REG_DATA_COLL, - REG_TRENDS_COLL, REG_BREAKDOWN_COLL, PROV_DATA_COLL, PROV_SERIES_COLL, - PROV_BREAKDOWN_COLL, PROV_TRENDS_COLL, REG_SERIES_COLL, TREND_CARDS, +from app import celery +from app.data import TREND_CARDS +from app.data.etl import load_df, augment_national_df, build_national_series, \ + build_trend, augment_regional_df, build_series, build_national_trends, \ + build_regional_breakdown, augment_provincial_df, \ + build_provincial_breakdowns, build_provincial_trends, \ + build_provincial_series, augment_vax_df, augment_summary_vax_df +from app.db import NAT_DATA_COLL, NAT_SERIES_COLL, NAT_TRENDS_COLL, \ + REG_DATA_COLL, REG_SERIES_COLL, REG_TRENDS_COLL, REG_BREAKDOWN_COLL, \ + PROV_DATA_COLL, PROV_BREAKDOWN_COLL, PROV_TRENDS_COLL, PROV_SERIES_COLL, \ VAX_COLL, VAX_SUMMARY_COLL -) -from app.data.etl import ( - load_df, build_series, build_national_trends, build_provincial_series, - build_provincial_trends, build_regional_breakdown, - build_provincial_breakdowns, build_national_series, build_trend, - augment_national_df, augment_regional_df, augment_provincial_df, - augment_vax_df, augment_summary_vax_df -) -from config import ( - DATE_KEY, PROVINCES, PROVINCE_KEY, REGIONS, REGION_KEY, - URL_PROVINCIAL, URL_REGIONAL, URL_NATIONAL, URL_VAX_DATA, - URL_VAX_ADMINS_SUMMARY_DATA, VAX_DATE_KEY -) +from constants import URL_NATIONAL, DATE_KEY, URL_REGIONAL, REGIONS, \ + REGION_KEY, URL_PROVINCIAL, PROVINCES, PROVINCE_KEY, URL_VAX_DATA, \ + VAX_DATE_KEY, URL_VAX_ADMINS_SUMMARY_DATA +@celery.task def update_national_collection(): """Update national collection""" response = {"status": "ko", "n_inserted_docs": 0, "errors": []} @@ -60,6 +57,7 @@ def update_national_collection(): return response +@celery.task def update_national_series_collection(): """Update national series collection""" response = {"status": "ko", "updated": False, "errors": []} @@ -85,6 +83,7 @@ def update_national_series_collection(): return response +@celery.task def update_national_trends_collection(): """Update national trends collection""" response = {"ids": [], "updated": False, "errors": []} @@ -112,6 +111,7 @@ def update_national_trends_collection(): return response +@celery.task def update_regional_collection(): """Update regional-data collection""" inserted_ids = [] @@ -143,6 +143,7 @@ def update_regional_collection(): return response +@celery.task def update_regional_series_collection(): """Update regional series collection""" n_docs = 0 @@ -183,6 +184,7 @@ def update_regional_series_collection(): return response +@celery.task def update_regional_trends_collection(): """Update regional trends collection""" n_docs = 0 @@ -217,6 +219,7 @@ def update_regional_trends_collection(): return response +@celery.task def update_regional_breakdown_collection(): """Update regional breakdown""" response = {"status": "ko", "updated": False, "errors": []} @@ -244,6 +247,7 @@ def update_regional_breakdown_collection(): return response +@celery.task def update_provincial_collection(): """Update provincial data collection""" response = {"status": "ko", "updated": False, "errors": [], "msg": ""} @@ -275,6 +279,7 @@ def update_provincial_collection(): return response +@celery.task def update_provincial_breakdown_collection(): """Update provincial breakdown""" n_docs = 0 @@ -308,6 +313,7 @@ def update_provincial_breakdown_collection(): return response +@celery.task def update_provincial_series_or_trends_collection(coll_type): """Update provincial series or trends collection""" n_docs = 0 @@ -350,6 +356,7 @@ def update_provincial_series_or_trends_collection(coll_type): return response +@celery.task def update_vax_collection(summary=False): """Update vax / vax_summary collection""" response = {"status": "ko", "n_inserted_docs": 0, "errors": []} diff --git a/app/plotter/__init__.py b/app/plotter/__init__.py index 4d44d9d..664e234 100644 --- a/app/plotter/__init__.py +++ b/app/plotter/__init__.py @@ -9,7 +9,7 @@ from flask_babel import gettext from app.data import get_national_data, get_region_data, get_province_data -from config import ( +from constants import ( REGION_KEY, REGIONS, PROVINCE_KEY, DATE_KEY, VARS, PROVINCES, KEY_PERIODS, TOTAL_CASES_KEY, NEW_POSITIVE_KEY, NEW_POSITIVE_MA_KEY ) diff --git a/app/ui/pandemic.py b/app/ui/pandemic.py index 3c19e7a..540740c 100644 --- a/app/ui/pandemic.py +++ b/app/ui/pandemic.py @@ -14,7 +14,7 @@ get_national_series, get_regional_series, get_provincial_series, get_positivity_idx, get_latest_update, enrich_frontend_data ) -from config import REGIONS, PROVINCES, ITALY_MAP, PAGE_BASE_TITLE +from constants import REGIONS, PROVINCES, ITALY_MAP, PAGE_BASE_TITLE URL_REGIONS = "/regions" URL_PROVINCES = "/provinces" diff --git a/app/ui/vaccines.py b/app/ui/vaccines.py index 565b894..05b7697 100644 --- a/app/ui/vaccines.py +++ b/app/ui/vaccines.py @@ -12,7 +12,7 @@ get_perc_pop_vax, get_admins_perc, get_admins_timeseries_chart_data ) from app.ui import vaccines -from config import PAGE_BASE_TITLE, ITALY_POPULATION, PC_TO_OD_MAP, REGIONS +from constants import PAGE_BASE_TITLE, ITALY_POPULATION, PC_TO_OD_MAP, REGIONS URL_VACCINES = "/vaccines" view_type = 'vaccines' diff --git a/app/utils/__init__.py b/app/utils/__init__.py index 8b308ea..5098b26 100644 --- a/app/utils/__init__.py +++ b/app/utils/__init__.py @@ -5,7 +5,7 @@ from flask_babel import gettext -from config import ITALY_MAP, RUBBISH_NOTE_REGEX +from constants import ITALY_MAP, RUBBISH_NOTE_REGEX def region_of_province(province_in: str) -> str: diff --git a/celery_worker.py b/celery_worker.py new file mode 100644 index 0000000..83b4564 --- /dev/null +++ b/celery_worker.py @@ -0,0 +1,14 @@ +""" +celery worker +""" +from app import create_app +from celery import Celery + +app = create_app() +app.app_context().push() +celery = Celery(__name__) +celery.config_from_object(app.config) +celery.conf.update( + broker_url=app.config['BROKER_URL'], + result_backend=app.config['RESULT_BACKEND'] +) diff --git a/config.py b/config.py index 5989d63..9b682e3 100644 --- a/config.py +++ b/config.py @@ -1,593 +1,42 @@ """ -General configuration file +Configuration """ -import datetime as dt import os -from collections import OrderedDict -from flask_babel import gettext +from dotenv import load_dotenv -VERSION = "4.0" -PAGE_BASE_TITLE = gettext("COVID-19 Italy") -HOSPITALIZED_WITH_SYMPTOMS_KEY = "ricoverati_con_sintomi" -ICU_KEY = "terapia_intensiva" -DAILY_ICU_KEY = "ingressi_terapia_intensiva" -DAILY_ICU_MA_KEY = "ingressi_terapia_intensiva_ma" -TOTAL_HOSPITALIZED_KEY = "totale_ospedalizzati" -DAILY_HOSPITALIZED_KEY = "totale_ospedalizzati_g" -DAILY_HOSPITALIZED_MA_KEY = "totale_ospedalizzati_g_ma" -SELF_ISOLATION_KEY = "isolamento_domiciliare" -TOTAL_POSITIVE_KEY = "totale_positivi" -NEW_POSITIVE_KEY = "nuovi_positivi" -NEW_POSITIVE_MA_KEY = "nuovi_positivi_ma" -TOTAL_HEALED_KEY = "dimessi_guariti" -TOTAL_DEATHS_KEY = "deceduti" -DAILY_DEATHS_KEY = "deceduti_g" -DAILY_DEATHS_MA_KEY = "deceduti_g_ma" -TOTAL_CASES_KEY = "totale_casi" -TOTAL_SWABS_KEY = "tamponi" -DAILY_SWABS_KEY = "tamponi_g" -DAILY_SWABS_MA_KEY = "tamponi_g_ma" -DAILY_POSITIVITY_INDEX = "indice_positivita" -REGION_KEY = "denominazione_regione" -PROVINCE_KEY = "denominazione_provincia" -REGION_CODE = "codice_regione" -PROVINCE_CODE = "codice_provincia" -VAX_LATEST_UPDATE_KEY = "ultimo_aggiornamento" -CP_DATE_FMT = "%Y-%m-%dT%H:%M:%S" -VAX_DATE_FMT = "%Y-%m-%dT%H:%M:%S.%f%z" -CHART_DATE_FMT = "%d %b %y" -UPDATE_FMT = "%d/%m/%Y" -VAX_UPDATE_FMT = "%d/%m/%Y %H:%M" -DATE_KEY = "data" -NOTE_KEY = "note" -STATE_KEY = "stato" -VAX_DATE_KEY = "data_somministrazione" -VAX_AREA_KEY = "area" -VAX_TYPE_KEY = "fornitore" -VAX_AGE_KEY = "fascia_anagrafica" -POP_KEY = "popolazione" -ADMINS_DOSES_KEY = "dosi_somministrate" -DELIVERED_DOSES_KEY = "dosi_consegnate" -VAX_ADMINS_PERC_KEY = "percentuale_somministrazione" -VAX_DAILY_ADMINS_KEY = "totale" -F_SEX_KEY = "sesso_femminile" -M_SEX_KEY = "sesso_maschile" -HEALTHCARE_PERS_KEY = "categoria_operatori_sanitari_sociosanitari" -NONHEALTHCARE_PERS_KEY = "categoria_personale_non_sanitario" -HFE_GUESTS_KEY = "categoria_ospiti_rsa" -OVER_80_KEY = "categoria_over80" -RUBBISH_NOTE_REGEX = r"[a-z][a-z]-[A-Z]\w+-[0-9][0-9][0-9][0-9]" -TRANSLATION_DIRNAME = "translations" -TREND_SYMBOL_LOGIC = { - "stable": { - "colour": "text-info", - "icon": "bi bi-dash", - "tooltip": gettext("Stable with respect to yesterday") - }, - "increase": { - "colour": "text-danger", - "icon": "bi bi-arrow-up-right", - "tooltip": gettext("Increased with respect to yesterday") - }, - "increase_inverted": { - "colour": "text-success", - "icon": "bi bi-arrow-up-right", - "tooltip": gettext("Increased with respect to yesterday") - }, - "decrease": { - "colour": "text-success", - "icon": "bi bi-arrow-down-left", - "tooltip": gettext("Decreased with respect to yesterday") - }, - "decrease_inverted": { - "colour": "text-danger", - "icon": "bi bi-arrow-down-left", - "tooltip": gettext("Decreased with respect to yesterday") - } -} -VARS = OrderedDict() +load_dotenv() -# Daily variables -VARS[NEW_POSITIVE_KEY] = { - "title": gettext("New Positive"), - "desc": gettext("Daily count of new positive cases"), - "longdesc": gettext("Daily count of new positive cases"), - "icon": "fas fa-head-side-cough", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_ICU_KEY] = { - "title": gettext("Daily ICU"), - "desc": gettext("# of people daily admitted in ICU"), - "longdesc": gettext("Daily count of people in ICU"), - "icon": "fas fa-procedures", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_DEATHS_KEY] = { - "title": gettext("Daily Deaths"), - "desc": gettext("Daily deaths count"), - "longdesc": gettext( - "Daily deaths count" - ), - "icon": "fas fa-cross", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_SWABS_KEY] = { - "title": gettext("Daily Swabs"), - "desc": gettext("# of swabs performed daily"), - "longdesc": gettext( - "Daily number of swabs performed" - ), - "icon": "fas fa-vial", - "increase": TREND_SYMBOL_LOGIC["increase_inverted"], - "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_HOSPITALIZED_KEY] = { - "title": gettext("Daily Hospitalized"), - "desc": gettext("# of people daily hospitalized"), - "longdesc": gettext( - "Daily count of people currently hospitalized. " - "It takes into account ICU"), - "icon": "fas fa-hospital-symbol", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[NEW_POSITIVE_MA_KEY] = { - "title": gettext("New Positive (7-day MA)"), - "desc": gettext("Daily count of new positve cases"), - "longdesc": gettext("Daily count of new positve cases"), - "icon": "fas fa-head-side-cough", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_DEATHS_MA_KEY] = { - "title": gettext("Daily Deaths (7-day MA)"), - "desc": gettext("Daily deaths count"), - "longdesc": gettext( - "Daily deaths count" - ), - "icon": "fas fa-cross", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_ICU_MA_KEY] = { - "title": gettext("Daily ICU (7-day MA)"), - "desc": gettext("# of people daily admitted in ICU"), - "longdesc": gettext("Daily count of people in ICU"), - "icon": "fas fa-procedures", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_SWABS_MA_KEY] = { - "title": gettext("Daily Swabs (7-day MA)"), - "desc": gettext("# of swabs performed daily"), - "longdesc": gettext( - "Daily number of swabs performed" - ), - "icon": "fas fa-vial", - "increase": TREND_SYMBOL_LOGIC["increase_inverted"], - "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -VARS[DAILY_HOSPITALIZED_MA_KEY] = { - "title": gettext("Daily Hospitalized (7-day MA)"), - "desc": gettext("# of people daily hospitalized"), - "longdesc": gettext( - "Daily count of people currently hospitalized. " - "It takes into account ICU"), - "icon": "fas fa-hospital-symbol", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "daily" -} -# Current-state variables -VARS[TOTAL_POSITIVE_KEY] = { - "title": gettext("Total Positive"), - "desc": gettext( - "# of people currently " - "hospitalized with symptoms + ICU + self isolation" - ), - "longdesc": gettext( - "People currently positive. " - "Unlike 'Total Cases' it does not take into account " - "'healed' and 'deaths'. By the end of the outbreak " - "this should tend to zero. In particular, it is: " - "total positive = total cases - total healed - total deaths" - ), - "icon": "fas fa-viruses", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "current" -} -VARS[ICU_KEY] = { - "title": gettext("Intensive Care Unit"), - "desc": gettext("# of people currently in ICU"), - "longdesc": gettext( - "Total count of people currently in ICU and positive to COVID-19" - ), - "icon": "fas fa-procedures", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "current" -} -VARS[HOSPITALIZED_WITH_SYMPTOMS_KEY] = { - "title": gettext("Hospitalized With Symptoms"), - "desc": gettext( - "# of people currently hospitalized with symptoms" - ), - "longdesc": gettext( - "Total count of people currently in hospital " - "due to coronavirus with symptoms" - ), - "icon": "fas fa-hospital-symbol", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "current" -} +class BaseConfig(object): + """Base config class.""" + API_KEY = os.environ.get('API_KEY') + BROKER_URL = os.environ.get('REDIS_URL') + RESULT_BACKEND = os.environ.get('REDIS_URL') + MONGO_URI = os.environ.get('MONGO_URI') + SITEMAP_INCLUDE_RULES_WITHOUT_PARAMS = True -VARS[TOTAL_HOSPITALIZED_KEY] = { - "title": gettext("Total Hospitalized"), - "desc": gettext("# of people currently hospitalized"), - "longdesc": gettext( - "Total count of people currently hospitalized. " - "It takes into account ICU"), - "icon": "fas fa-hospital-symbol", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "current" -} -VARS[SELF_ISOLATION_KEY] = { - "title": gettext("Self Isolation"), - "desc": gettext("# of people currently in self isolation"), - "longdesc": gettext( - "People currently positive but who do not need hospitalization" - ), - "icon": "fas fa-house-user", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "current" -} -# Cumulative variables -VARS[TOTAL_CASES_KEY] = { - "title": gettext("Total Cases"), - "desc": gettext( - "Total count of the positive tests since the" - " beginning of the outbreak" - ), - "longdesc": gettext( - "Total count of the positive tests since the" - " beginning of the outbreak" - ), - "icon": "fas fa-viruses", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "cum" -} -VARS[TOTAL_DEATHS_KEY] = { - "title": gettext("Total Deaths"), - "desc": gettext("Total deaths count"), - "longdesc": gettext( - "Total deaths count since the beginning of the outbreak" - ), - "icon": "fas fa-cross", - "increase": TREND_SYMBOL_LOGIC["increase"], - "decrease": TREND_SYMBOL_LOGIC["decrease"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "cum" -} +class Development(BaseConfig): + """Development config.""" + DEBUG = True + ENV = 'dev' -VARS[TOTAL_SWABS_KEY] = { - "title": gettext("Total Swabs"), - "desc": gettext("# of swabs performed"), - "longdesc": gettext( - "Total number of swabs performed since the beginning of the outbreak" - ), - "icon": "fas fa-vial", - "increase": TREND_SYMBOL_LOGIC["increase_inverted"], - "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "cum" -} -VARS[TOTAL_HEALED_KEY] = { - "title": gettext("Total Healed"), - "desc": gettext("Cumulative # of people healed"), - "longdesc": gettext( - "Total number of people healed since the beginning of the outbreak" - ), - "icon": "fas fa-smile", - "increase": TREND_SYMBOL_LOGIC["increase_inverted"], - "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], - "stable": TREND_SYMBOL_LOGIC["stable"], - "type": "cum" -} -# Vax variables -VARS[HEALTHCARE_PERS_KEY] = { - "title": gettext("Healthcare Personnel"), - "type": "vax" -} -VARS[NONHEALTHCARE_PERS_KEY] = { - "title": gettext("Non-healthcare Personnel"), - "type": "vax" -} -VARS[HFE_GUESTS_KEY] = { - "title": gettext("HFE Guests"), - "type": "vax" -} -VARS[OVER_80_KEY] = { - "title": gettext("Over 80"), - "type": "vax" -} +class Staging(BaseConfig): + """Staging config.""" + DEBUG = True + ENV = 'staging' -# Data URLs: Pandemic -BASE_URL_DATA = ( - "https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/" -) -NATIONAL_DATA_FILE = ( - "dati-andamento-nazionale/dpc-covid19-ita-andamento-nazionale.csv") -REGIONAL_DATA_FILE = "dati-regioni/dpc-covid19-ita-regioni.csv" -REGIONAL_LATEST_DATA_FILE = "dati-regioni/dpc-covid19-ita-regioni-latest.csv" -PROVINCIAL_DATE_FILE = "dati-province/dpc-covid19-ita-province.csv" -URL_NATIONAL = os.path.join(BASE_URL_DATA, NATIONAL_DATA_FILE) -URL_REGIONAL = os.path.join(BASE_URL_DATA, REGIONAL_DATA_FILE) -URL_PROVINCIAL = os.path.join(BASE_URL_DATA, PROVINCIAL_DATE_FILE) -URL_REGIONAL_LATEST = os.path.join(BASE_URL_DATA, REGIONAL_LATEST_DATA_FILE) +class Production(BaseConfig): + """Production config""" + DEBUG = False + ENV = 'production' -# Data URLs: Vaccines -BASE_URL_VAX_DATA = ( - "https://raw.githubusercontent.com/" - "italia/covid19-opendata-vaccini/master/dati/" -) -VAX_FILE = "somministrazioni-vaccini-latest.csv" -VAX_ADMINS_SUMMARY_FILE = "somministrazioni-vaccini-summary-latest.csv" -VAX_SUMMARY_FILE = "vaccini-summary-latest.csv" -VAX_LATEST_UPDATE_JSON = "last-update-dataset.json" -URL_VAX_DATA = os.path.join(BASE_URL_VAX_DATA, VAX_FILE) -URL_VAX_LATEST_UPDATE = os.path.join(BASE_URL_VAX_DATA, VAX_LATEST_UPDATE_JSON) -URL_VAX_SUMMARY_DATA = os.path.join(BASE_URL_VAX_DATA, VAX_SUMMARY_FILE) -URL_VAX_ADMINS_SUMMARY_DATA = os.path.join( - BASE_URL_VAX_DATA, VAX_ADMINS_SUMMARY_FILE) -# Key Dates -LOCKDOWN_DAY = dt.datetime(2020, 3, 9) -PHASE2_DAY = dt.datetime(2020, 5, 4) -PHASE3_DAY = dt.datetime(2020, 6, 15) -CRITICAL_AREAS_DAY = dt.datetime(2020, 11, 6) -VACCINE_DAY = dt.datetime(2020, 12, 27) -# Key Periods -KEY_PERIODS = OrderedDict() -KEY_PERIODS["lockdown"] = { - "title": gettext("Lockdown"), - "text": gettext('Days in Lockdown'), - "color": "red", - "from": LOCKDOWN_DAY, - "to": PHASE2_DAY, - "n_days": (PHASE2_DAY - LOCKDOWN_DAY).days -} -KEY_PERIODS["phase2"] = { - "title": gettext("Phase 2"), - "text": gettext('Days in "Phase 2"'), - "color": "orange", - "from": PHASE2_DAY, - "to": PHASE3_DAY, - "n_days": (PHASE3_DAY - PHASE2_DAY).days, -} -KEY_PERIODS["phase3"] = { - "title": gettext("Phase 3"), - "text": gettext('Days in "Phase 3"'), - "color": "green", - "from": PHASE3_DAY, - "to": CRITICAL_AREAS_DAY, - "n_days": (CRITICAL_AREAS_DAY - PHASE3_DAY).days, -} -KEY_PERIODS["critical_areas"] = { - "title": gettext("Critical Areas"), - "text": gettext('Days since "Critical areas"'), - "color": "red", - "from": CRITICAL_AREAS_DAY, - "to": dt.datetime.today(), - "n_days": (dt.datetime.today() - CRITICAL_AREAS_DAY).days -} -KEY_PERIODS["vaccine_day"] = { - "title": gettext("Vaccine day"), - "text": gettext('Days since "Vaccine day"'), - "color": "blue", - "from": VACCINE_DAY, - "to": dt.datetime.today(), - "n_days": (dt.datetime.today() - VACCINE_DAY).days -} - -LANGUAGES = { - "en": "English", - "it_IT": "Italiano" -} - -ITALY_MAP = { - 'Abruzzo': ['Chieti', "L'Aquila", 'Pescara', 'Teramo'], - 'Basilicata': ['Matera', 'Potenza'], - 'Calabria': ['Catanzaro', - 'Cosenza', - 'Crotone', - 'Reggio di Calabria', - 'Vibo Valentia'], - 'Campania': ['Avellino', 'Benevento', 'Caserta', 'Napoli', 'Salerno'], - 'Emilia-Romagna': ['Bologna', - 'Ferrara', - 'Forlì-Cesena', - 'Modena', - 'Parma', - 'Piacenza', - 'Ravenna', - "Reggio nell'Emilia", - 'Rimini'], - 'Friuli Venezia Giulia': ['Gorizia', 'Pordenone', 'Trieste', 'Udine'], - 'Lazio': ['Frosinone', 'Latina', 'Rieti', 'Roma', 'Viterbo'], - 'Liguria': ['Genova', 'Imperia', 'La Spezia', 'Savona'], - 'Lombardia': ['Bergamo', - 'Brescia', - 'Como', - 'Cremona', - 'Lecco', - 'Lodi', - 'Mantova', - 'Milano', - 'Monza e della Brianza', - 'Pavia', - 'Sondrio', - 'Varese'], - 'Marche': ['Ancona', 'Ascoli Piceno', 'Fermo', 'Macerata', - 'Pesaro e Urbino'], - 'Molise': ['Campobasso', 'Isernia'], - 'Piemonte': ['Alessandria', - 'Asti', - 'Biella', - 'Cuneo', - 'Novara', - 'Torino', - 'Verbano-Cusio-Ossola', - 'Vercelli'], - 'Puglia': ['Bari', - 'Barletta-Andria-Trani', - 'Brindisi', - 'Lecce', - 'Foggia', - 'Taranto'], - 'Sardegna': ['Cagliari', - 'Nuoro', - 'Sassari', - 'Sud Sardegna'], - 'Sicilia': ['Agrigento', - 'Caltanissetta', - 'Catania', - 'Enna', - 'Messina', - 'Palermo', - 'Ragusa', - 'Siracusa', - 'Trapani'], - 'Toscana': ['Arezzo', - 'Firenze', - 'Grosseto', - 'Livorno', - 'Lucca', - 'Massa Carrara', - 'Pisa', - 'Pistoia', - 'Prato', - 'Siena'], - 'P.A. Bolzano': [], - 'P.A. Trento': [], - 'Umbria': ['Perugia', 'Terni'], - "Valle d'Aosta": ['Aosta'], - 'Veneto': ['Belluno', - 'Padova', - 'Rovigo', - 'Treviso', - 'Venezia', - 'Verona', - 'Vicenza'] -} -REGIONS = [key for key in ITALY_MAP] -PROVINCES = [p for pp in ITALY_MAP.values() for p in pp] -ITALY_POPULATION = { - 'Piemonte': 4311217, - "Valle d'Aosta": 125034, - 'Lombardia': 10027602, - 'P.A. Bolzano': 532250, - 'P.A. Trento': 542214, - 'Veneto': 4879133, - 'Friuli Venezia Giulia': 1206216, - 'Liguria': 1524826, - 'Emilia-Romagna': 4464119, - 'Toscana': 3692555, - 'Umbria': 870165, - 'Marche': 1512672, - 'Lazio': 5755700, - 'Abruzzo': 1293941, - 'Molise': 300516, - 'Campania': 5712143, - 'Puglia': 3953305, - 'Basilicata': 553254, - 'Calabria': 1894110, - 'Sicilia': 4875290, - 'Sardegna': 1611621, - 'Italia': 59641488 -} -PC_TO_OD_MAP = { - 'Italia': 'ITA', - 'Abruzzo': 'ABR', - 'Basilicata': 'BAS', - 'Calabria': 'CAL', - 'Campania': 'CAM', - 'Emilia-Romagna': 'EMR', - 'Friuli Venezia Giulia': 'FVG', - 'Lazio': 'LAZ', - 'Liguria': 'LIG', - 'Lombardia': 'LOM', - 'Marche': 'MAR', - 'Molise': 'MOL', - 'P.A. Bolzano': 'PAB', - 'P.A. Trento': 'PAT', - 'Piemonte': 'PIE', - 'Puglia': 'PUG', - 'Sardegna': 'SAR', - 'Sicilia': 'SIC', - 'Toscana': 'TOS', - 'Umbria': 'UMB', - "Valle d'Aosta": 'VDA', - 'Veneto': 'VEN', -} -OD_TO_PC_MAP = { - 'ITA': 'Italia', - 'ABR': 'Abruzzo', - 'BAS': 'Basilicata', - 'CAL': 'Calabria', - 'CAM': 'Campania', - 'EMR': 'Emilia-Romagna', - 'FVG': 'Friuli Venezia Giulia', - 'LAZ': 'Lazio', - 'LIG': 'Liguria', - 'LOM': 'Lombardia', - 'MAR': 'Marche', - 'MOL': 'Molise', - 'PAB': 'P.A. Bolzano', - 'PAT': 'P.A. Trento', - 'PIE': 'Piemonte', - 'PUG': 'Puglia', - 'SAR': 'Sardegna', - 'SIC': 'Sicilia', - 'TOS': 'Toscana', - 'UMB': 'Umbria', - 'VDA': "Valle d'Aosta", - 'VEN': 'Veneto' +config = { + 'development': Development, + 'staging': Staging, + 'production': Production, } diff --git a/constants.py b/constants.py new file mode 100644 index 0000000..5989d63 --- /dev/null +++ b/constants.py @@ -0,0 +1,593 @@ +""" +General configuration file +""" +import datetime as dt +import os +from collections import OrderedDict + +from flask_babel import gettext + +VERSION = "4.0" +PAGE_BASE_TITLE = gettext("COVID-19 Italy") +HOSPITALIZED_WITH_SYMPTOMS_KEY = "ricoverati_con_sintomi" +ICU_KEY = "terapia_intensiva" +DAILY_ICU_KEY = "ingressi_terapia_intensiva" +DAILY_ICU_MA_KEY = "ingressi_terapia_intensiva_ma" +TOTAL_HOSPITALIZED_KEY = "totale_ospedalizzati" +DAILY_HOSPITALIZED_KEY = "totale_ospedalizzati_g" +DAILY_HOSPITALIZED_MA_KEY = "totale_ospedalizzati_g_ma" +SELF_ISOLATION_KEY = "isolamento_domiciliare" +TOTAL_POSITIVE_KEY = "totale_positivi" +NEW_POSITIVE_KEY = "nuovi_positivi" +NEW_POSITIVE_MA_KEY = "nuovi_positivi_ma" +TOTAL_HEALED_KEY = "dimessi_guariti" +TOTAL_DEATHS_KEY = "deceduti" +DAILY_DEATHS_KEY = "deceduti_g" +DAILY_DEATHS_MA_KEY = "deceduti_g_ma" +TOTAL_CASES_KEY = "totale_casi" +TOTAL_SWABS_KEY = "tamponi" +DAILY_SWABS_KEY = "tamponi_g" +DAILY_SWABS_MA_KEY = "tamponi_g_ma" +DAILY_POSITIVITY_INDEX = "indice_positivita" +REGION_KEY = "denominazione_regione" +PROVINCE_KEY = "denominazione_provincia" +REGION_CODE = "codice_regione" +PROVINCE_CODE = "codice_provincia" +VAX_LATEST_UPDATE_KEY = "ultimo_aggiornamento" +CP_DATE_FMT = "%Y-%m-%dT%H:%M:%S" +VAX_DATE_FMT = "%Y-%m-%dT%H:%M:%S.%f%z" +CHART_DATE_FMT = "%d %b %y" +UPDATE_FMT = "%d/%m/%Y" +VAX_UPDATE_FMT = "%d/%m/%Y %H:%M" +DATE_KEY = "data" +NOTE_KEY = "note" +STATE_KEY = "stato" +VAX_DATE_KEY = "data_somministrazione" +VAX_AREA_KEY = "area" +VAX_TYPE_KEY = "fornitore" +VAX_AGE_KEY = "fascia_anagrafica" +POP_KEY = "popolazione" +ADMINS_DOSES_KEY = "dosi_somministrate" +DELIVERED_DOSES_KEY = "dosi_consegnate" +VAX_ADMINS_PERC_KEY = "percentuale_somministrazione" +VAX_DAILY_ADMINS_KEY = "totale" +F_SEX_KEY = "sesso_femminile" +M_SEX_KEY = "sesso_maschile" +HEALTHCARE_PERS_KEY = "categoria_operatori_sanitari_sociosanitari" +NONHEALTHCARE_PERS_KEY = "categoria_personale_non_sanitario" +HFE_GUESTS_KEY = "categoria_ospiti_rsa" +OVER_80_KEY = "categoria_over80" +RUBBISH_NOTE_REGEX = r"[a-z][a-z]-[A-Z]\w+-[0-9][0-9][0-9][0-9]" +TRANSLATION_DIRNAME = "translations" +TREND_SYMBOL_LOGIC = { + "stable": { + "colour": "text-info", + "icon": "bi bi-dash", + "tooltip": gettext("Stable with respect to yesterday") + }, + "increase": { + "colour": "text-danger", + "icon": "bi bi-arrow-up-right", + "tooltip": gettext("Increased with respect to yesterday") + }, + "increase_inverted": { + "colour": "text-success", + "icon": "bi bi-arrow-up-right", + "tooltip": gettext("Increased with respect to yesterday") + }, + "decrease": { + "colour": "text-success", + "icon": "bi bi-arrow-down-left", + "tooltip": gettext("Decreased with respect to yesterday") + }, + "decrease_inverted": { + "colour": "text-danger", + "icon": "bi bi-arrow-down-left", + "tooltip": gettext("Decreased with respect to yesterday") + } +} +VARS = OrderedDict() + +# Daily variables +VARS[NEW_POSITIVE_KEY] = { + "title": gettext("New Positive"), + "desc": gettext("Daily count of new positive cases"), + "longdesc": gettext("Daily count of new positive cases"), + "icon": "fas fa-head-side-cough", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_ICU_KEY] = { + "title": gettext("Daily ICU"), + "desc": gettext("# of people daily admitted in ICU"), + "longdesc": gettext("Daily count of people in ICU"), + "icon": "fas fa-procedures", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_DEATHS_KEY] = { + "title": gettext("Daily Deaths"), + "desc": gettext("Daily deaths count"), + "longdesc": gettext( + "Daily deaths count" + ), + "icon": "fas fa-cross", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_SWABS_KEY] = { + "title": gettext("Daily Swabs"), + "desc": gettext("# of swabs performed daily"), + "longdesc": gettext( + "Daily number of swabs performed" + ), + "icon": "fas fa-vial", + "increase": TREND_SYMBOL_LOGIC["increase_inverted"], + "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_HOSPITALIZED_KEY] = { + "title": gettext("Daily Hospitalized"), + "desc": gettext("# of people daily hospitalized"), + "longdesc": gettext( + "Daily count of people currently hospitalized. " + "It takes into account ICU"), + "icon": "fas fa-hospital-symbol", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[NEW_POSITIVE_MA_KEY] = { + "title": gettext("New Positive (7-day MA)"), + "desc": gettext("Daily count of new positve cases"), + "longdesc": gettext("Daily count of new positve cases"), + "icon": "fas fa-head-side-cough", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_DEATHS_MA_KEY] = { + "title": gettext("Daily Deaths (7-day MA)"), + "desc": gettext("Daily deaths count"), + "longdesc": gettext( + "Daily deaths count" + ), + "icon": "fas fa-cross", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_ICU_MA_KEY] = { + "title": gettext("Daily ICU (7-day MA)"), + "desc": gettext("# of people daily admitted in ICU"), + "longdesc": gettext("Daily count of people in ICU"), + "icon": "fas fa-procedures", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_SWABS_MA_KEY] = { + "title": gettext("Daily Swabs (7-day MA)"), + "desc": gettext("# of swabs performed daily"), + "longdesc": gettext( + "Daily number of swabs performed" + ), + "icon": "fas fa-vial", + "increase": TREND_SYMBOL_LOGIC["increase_inverted"], + "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} +VARS[DAILY_HOSPITALIZED_MA_KEY] = { + "title": gettext("Daily Hospitalized (7-day MA)"), + "desc": gettext("# of people daily hospitalized"), + "longdesc": gettext( + "Daily count of people currently hospitalized. " + "It takes into account ICU"), + "icon": "fas fa-hospital-symbol", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "daily" +} + +# Current-state variables +VARS[TOTAL_POSITIVE_KEY] = { + "title": gettext("Total Positive"), + "desc": gettext( + "# of people currently " + "hospitalized with symptoms + ICU + self isolation" + ), + "longdesc": gettext( + "People currently positive. " + "Unlike 'Total Cases' it does not take into account " + "'healed' and 'deaths'. By the end of the outbreak " + "this should tend to zero. In particular, it is: " + "total positive = total cases - total healed - total deaths" + ), + "icon": "fas fa-viruses", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "current" +} +VARS[ICU_KEY] = { + "title": gettext("Intensive Care Unit"), + "desc": gettext("# of people currently in ICU"), + "longdesc": gettext( + "Total count of people currently in ICU and positive to COVID-19" + ), + "icon": "fas fa-procedures", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "current" +} +VARS[HOSPITALIZED_WITH_SYMPTOMS_KEY] = { + "title": gettext("Hospitalized With Symptoms"), + "desc": gettext( + "# of people currently hospitalized with symptoms" + ), + "longdesc": gettext( + "Total count of people currently in hospital " + "due to coronavirus with symptoms" + ), + "icon": "fas fa-hospital-symbol", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "current" +} + +VARS[TOTAL_HOSPITALIZED_KEY] = { + "title": gettext("Total Hospitalized"), + "desc": gettext("# of people currently hospitalized"), + "longdesc": gettext( + "Total count of people currently hospitalized. " + "It takes into account ICU"), + "icon": "fas fa-hospital-symbol", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "current" +} +VARS[SELF_ISOLATION_KEY] = { + "title": gettext("Self Isolation"), + "desc": gettext("# of people currently in self isolation"), + "longdesc": gettext( + "People currently positive but who do not need hospitalization" + ), + "icon": "fas fa-house-user", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "current" +} + +# Cumulative variables +VARS[TOTAL_CASES_KEY] = { + "title": gettext("Total Cases"), + "desc": gettext( + "Total count of the positive tests since the" + " beginning of the outbreak" + ), + "longdesc": gettext( + "Total count of the positive tests since the" + " beginning of the outbreak" + ), + "icon": "fas fa-viruses", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "cum" +} +VARS[TOTAL_DEATHS_KEY] = { + "title": gettext("Total Deaths"), + "desc": gettext("Total deaths count"), + "longdesc": gettext( + "Total deaths count since the beginning of the outbreak" + ), + "icon": "fas fa-cross", + "increase": TREND_SYMBOL_LOGIC["increase"], + "decrease": TREND_SYMBOL_LOGIC["decrease"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "cum" +} + +VARS[TOTAL_SWABS_KEY] = { + "title": gettext("Total Swabs"), + "desc": gettext("# of swabs performed"), + "longdesc": gettext( + "Total number of swabs performed since the beginning of the outbreak" + ), + "icon": "fas fa-vial", + "increase": TREND_SYMBOL_LOGIC["increase_inverted"], + "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "cum" +} +VARS[TOTAL_HEALED_KEY] = { + "title": gettext("Total Healed"), + "desc": gettext("Cumulative # of people healed"), + "longdesc": gettext( + "Total number of people healed since the beginning of the outbreak" + ), + "icon": "fas fa-smile", + "increase": TREND_SYMBOL_LOGIC["increase_inverted"], + "decrease": TREND_SYMBOL_LOGIC["decrease_inverted"], + "stable": TREND_SYMBOL_LOGIC["stable"], + "type": "cum" +} + +# Vax variables +VARS[HEALTHCARE_PERS_KEY] = { + "title": gettext("Healthcare Personnel"), + "type": "vax" +} +VARS[NONHEALTHCARE_PERS_KEY] = { + "title": gettext("Non-healthcare Personnel"), + "type": "vax" +} +VARS[HFE_GUESTS_KEY] = { + "title": gettext("HFE Guests"), + "type": "vax" +} +VARS[OVER_80_KEY] = { + "title": gettext("Over 80"), + "type": "vax" +} + +# Data URLs: Pandemic +BASE_URL_DATA = ( + "https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/" +) +NATIONAL_DATA_FILE = ( + "dati-andamento-nazionale/dpc-covid19-ita-andamento-nazionale.csv") +REGIONAL_DATA_FILE = "dati-regioni/dpc-covid19-ita-regioni.csv" +REGIONAL_LATEST_DATA_FILE = "dati-regioni/dpc-covid19-ita-regioni-latest.csv" +PROVINCIAL_DATE_FILE = "dati-province/dpc-covid19-ita-province.csv" + +URL_NATIONAL = os.path.join(BASE_URL_DATA, NATIONAL_DATA_FILE) +URL_REGIONAL = os.path.join(BASE_URL_DATA, REGIONAL_DATA_FILE) +URL_PROVINCIAL = os.path.join(BASE_URL_DATA, PROVINCIAL_DATE_FILE) +URL_REGIONAL_LATEST = os.path.join(BASE_URL_DATA, REGIONAL_LATEST_DATA_FILE) + +# Data URLs: Vaccines +BASE_URL_VAX_DATA = ( + "https://raw.githubusercontent.com/" + "italia/covid19-opendata-vaccini/master/dati/" +) +VAX_FILE = "somministrazioni-vaccini-latest.csv" +VAX_ADMINS_SUMMARY_FILE = "somministrazioni-vaccini-summary-latest.csv" +VAX_SUMMARY_FILE = "vaccini-summary-latest.csv" +VAX_LATEST_UPDATE_JSON = "last-update-dataset.json" +URL_VAX_DATA = os.path.join(BASE_URL_VAX_DATA, VAX_FILE) +URL_VAX_LATEST_UPDATE = os.path.join(BASE_URL_VAX_DATA, VAX_LATEST_UPDATE_JSON) +URL_VAX_SUMMARY_DATA = os.path.join(BASE_URL_VAX_DATA, VAX_SUMMARY_FILE) +URL_VAX_ADMINS_SUMMARY_DATA = os.path.join( + BASE_URL_VAX_DATA, VAX_ADMINS_SUMMARY_FILE) +# Key Dates +LOCKDOWN_DAY = dt.datetime(2020, 3, 9) +PHASE2_DAY = dt.datetime(2020, 5, 4) +PHASE3_DAY = dt.datetime(2020, 6, 15) +CRITICAL_AREAS_DAY = dt.datetime(2020, 11, 6) +VACCINE_DAY = dt.datetime(2020, 12, 27) + +# Key Periods +KEY_PERIODS = OrderedDict() +KEY_PERIODS["lockdown"] = { + "title": gettext("Lockdown"), + "text": gettext('Days in Lockdown'), + "color": "red", + "from": LOCKDOWN_DAY, + "to": PHASE2_DAY, + "n_days": (PHASE2_DAY - LOCKDOWN_DAY).days +} +KEY_PERIODS["phase2"] = { + "title": gettext("Phase 2"), + "text": gettext('Days in "Phase 2"'), + "color": "orange", + "from": PHASE2_DAY, + "to": PHASE3_DAY, + "n_days": (PHASE3_DAY - PHASE2_DAY).days, +} +KEY_PERIODS["phase3"] = { + "title": gettext("Phase 3"), + "text": gettext('Days in "Phase 3"'), + "color": "green", + "from": PHASE3_DAY, + "to": CRITICAL_AREAS_DAY, + "n_days": (CRITICAL_AREAS_DAY - PHASE3_DAY).days, +} +KEY_PERIODS["critical_areas"] = { + "title": gettext("Critical Areas"), + "text": gettext('Days since "Critical areas"'), + "color": "red", + "from": CRITICAL_AREAS_DAY, + "to": dt.datetime.today(), + "n_days": (dt.datetime.today() - CRITICAL_AREAS_DAY).days +} +KEY_PERIODS["vaccine_day"] = { + "title": gettext("Vaccine day"), + "text": gettext('Days since "Vaccine day"'), + "color": "blue", + "from": VACCINE_DAY, + "to": dt.datetime.today(), + "n_days": (dt.datetime.today() - VACCINE_DAY).days +} + +LANGUAGES = { + "en": "English", + "it_IT": "Italiano" +} + +ITALY_MAP = { + 'Abruzzo': ['Chieti', "L'Aquila", 'Pescara', 'Teramo'], + 'Basilicata': ['Matera', 'Potenza'], + 'Calabria': ['Catanzaro', + 'Cosenza', + 'Crotone', + 'Reggio di Calabria', + 'Vibo Valentia'], + 'Campania': ['Avellino', 'Benevento', 'Caserta', 'Napoli', 'Salerno'], + 'Emilia-Romagna': ['Bologna', + 'Ferrara', + 'Forlì-Cesena', + 'Modena', + 'Parma', + 'Piacenza', + 'Ravenna', + "Reggio nell'Emilia", + 'Rimini'], + 'Friuli Venezia Giulia': ['Gorizia', 'Pordenone', 'Trieste', 'Udine'], + 'Lazio': ['Frosinone', 'Latina', 'Rieti', 'Roma', 'Viterbo'], + 'Liguria': ['Genova', 'Imperia', 'La Spezia', 'Savona'], + 'Lombardia': ['Bergamo', + 'Brescia', + 'Como', + 'Cremona', + 'Lecco', + 'Lodi', + 'Mantova', + 'Milano', + 'Monza e della Brianza', + 'Pavia', + 'Sondrio', + 'Varese'], + 'Marche': ['Ancona', 'Ascoli Piceno', 'Fermo', 'Macerata', + 'Pesaro e Urbino'], + 'Molise': ['Campobasso', 'Isernia'], + 'Piemonte': ['Alessandria', + 'Asti', + 'Biella', + 'Cuneo', + 'Novara', + 'Torino', + 'Verbano-Cusio-Ossola', + 'Vercelli'], + 'Puglia': ['Bari', + 'Barletta-Andria-Trani', + 'Brindisi', + 'Lecce', + 'Foggia', + 'Taranto'], + 'Sardegna': ['Cagliari', + 'Nuoro', + 'Sassari', + 'Sud Sardegna'], + 'Sicilia': ['Agrigento', + 'Caltanissetta', + 'Catania', + 'Enna', + 'Messina', + 'Palermo', + 'Ragusa', + 'Siracusa', + 'Trapani'], + 'Toscana': ['Arezzo', + 'Firenze', + 'Grosseto', + 'Livorno', + 'Lucca', + 'Massa Carrara', + 'Pisa', + 'Pistoia', + 'Prato', + 'Siena'], + 'P.A. Bolzano': [], + 'P.A. Trento': [], + 'Umbria': ['Perugia', 'Terni'], + "Valle d'Aosta": ['Aosta'], + 'Veneto': ['Belluno', + 'Padova', + 'Rovigo', + 'Treviso', + 'Venezia', + 'Verona', + 'Vicenza'] +} +REGIONS = [key for key in ITALY_MAP] +PROVINCES = [p for pp in ITALY_MAP.values() for p in pp] +ITALY_POPULATION = { + 'Piemonte': 4311217, + "Valle d'Aosta": 125034, + 'Lombardia': 10027602, + 'P.A. Bolzano': 532250, + 'P.A. Trento': 542214, + 'Veneto': 4879133, + 'Friuli Venezia Giulia': 1206216, + 'Liguria': 1524826, + 'Emilia-Romagna': 4464119, + 'Toscana': 3692555, + 'Umbria': 870165, + 'Marche': 1512672, + 'Lazio': 5755700, + 'Abruzzo': 1293941, + 'Molise': 300516, + 'Campania': 5712143, + 'Puglia': 3953305, + 'Basilicata': 553254, + 'Calabria': 1894110, + 'Sicilia': 4875290, + 'Sardegna': 1611621, + 'Italia': 59641488 +} +PC_TO_OD_MAP = { + 'Italia': 'ITA', + 'Abruzzo': 'ABR', + 'Basilicata': 'BAS', + 'Calabria': 'CAL', + 'Campania': 'CAM', + 'Emilia-Romagna': 'EMR', + 'Friuli Venezia Giulia': 'FVG', + 'Lazio': 'LAZ', + 'Liguria': 'LIG', + 'Lombardia': 'LOM', + 'Marche': 'MAR', + 'Molise': 'MOL', + 'P.A. Bolzano': 'PAB', + 'P.A. Trento': 'PAT', + 'Piemonte': 'PIE', + 'Puglia': 'PUG', + 'Sardegna': 'SAR', + 'Sicilia': 'SIC', + 'Toscana': 'TOS', + 'Umbria': 'UMB', + "Valle d'Aosta": 'VDA', + 'Veneto': 'VEN', +} +OD_TO_PC_MAP = { + 'ITA': 'Italia', + 'ABR': 'Abruzzo', + 'BAS': 'Basilicata', + 'CAL': 'Calabria', + 'CAM': 'Campania', + 'EMR': 'Emilia-Romagna', + 'FVG': 'Friuli Venezia Giulia', + 'LAZ': 'Lazio', + 'LIG': 'Liguria', + 'LOM': 'Lombardia', + 'MAR': 'Marche', + 'MOL': 'Molise', + 'PAB': 'P.A. Bolzano', + 'PAT': 'P.A. Trento', + 'PIE': 'Piemonte', + 'PUG': 'Puglia', + 'SAR': 'Sardegna', + 'SIC': 'Sicilia', + 'TOS': 'Toscana', + 'UMB': 'Umbria', + 'VDA': "Valle d'Aosta", + 'VEN': 'Veneto' +} diff --git a/requirements.txt b/requirements.txt index 0b3dd7e..771f3c1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,5 @@ python-dotenv==0.15.0 click==7.1.2 Flask-Compress==1.8.0 pytz==2020.1 +celery==5.0.5 +redis==3.5.3